From 9314751e5c7470a654d26ff6dc4724a8c85f56d0 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 26 Feb 2020 10:36:35 +0200 Subject: [PATCH 0001/1830] FIX: Claim reviewable button did not show up for all topics Follow-up to 514c22e64b8b3aa95dde0456116fad5b954df384. --- .../discourse/components/reviewable-item.js.es6 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 index 786f7d5440..607bd75612 100644 --- a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 @@ -22,9 +22,13 @@ export default Component.extend({ return type.dasherize(); }, - @discourseComputed("reviewable.topic_id", "reviewable.removed_topic_id") - topicId(topicId, removedTopicId) { - return topicId || removedTopicId; + @discourseComputed( + "reviewable.topic", + "reviewable.topic_id", + "reviewable.removed_topic_id" + ) + topicId(topic, topicId, removedTopicId) { + return topic.id || topicId || removedTopicId; }, @discourseComputed("siteSettings.reviewable_claiming", "topicId") From 3568f296a3477d3f17ee2a63a247a3dc8e49c900 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 26 Feb 2020 10:46:10 +0200 Subject: [PATCH 0002/1830] FIX: Another attempt at fixing reviewable claiming Follow-up to 9314751e5c7470a654d26ff6dc4724a8c85f56d0. --- .../javascripts/discourse/components/reviewable-item.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 index 607bd75612..c301f1aa93 100644 --- a/app/assets/javascripts/discourse/components/reviewable-item.js.es6 +++ b/app/assets/javascripts/discourse/components/reviewable-item.js.es6 @@ -28,7 +28,7 @@ export default Component.extend({ "reviewable.removed_topic_id" ) topicId(topic, topicId, removedTopicId) { - return topic.id || topicId || removedTopicId; + return (topic && topic.id) || topicId || removedTopicId; }, @discourseComputed("siteSettings.reviewable_claiming", "topicId") From 87b2871074d0ef575f8ab47ccfa6545ce2ddd335 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 26 Feb 2020 22:08:39 +0300 Subject: [PATCH 0003/1830] Build(deps): Bump logster from 2.6.3 to 2.7.0 (#9050) This includes a new feature that allows you to control the length of log messages via `Logster.config.maximum_message_length`. More details at: https://github.com/discourse/logster/commit/e5c4fc0b6ee6fe662094a6d8dc7281c7bcd343c3 Bumps [logster](https://github.com/discourse/logster) from 2.6.3 to 2.7.0. - [Release notes](https://github.com/discourse/logster/releases) - [Changelog](https://github.com/discourse/logster/blob/master/CHANGELOG.md) - [Commits](https://github.com/discourse/logster/compare/v2.6.3...v2.7.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 013a17c384..56b4d03c26 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,7 +171,7 @@ GEM logstash-event (1.2.02) logstash-logger (0.26.1) logstash-event (~> 1.2) - logster (2.6.3) + logster (2.7.0) loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) From 9f528f0ec2f929046606de709b473fc5241270cb Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Wed, 26 Feb 2020 16:56:11 -0500 Subject: [PATCH 0004/1830] Version bump to v2.5.0.beta1 --- lib/version.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/version.rb b/lib/version.rb index 48151a9be9..85a9a0503c 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -7,9 +7,9 @@ module Discourse unless defined? ::Discourse::VERSION module VERSION #:nodoc: MAJOR = 2 - MINOR = 4 + MINOR = 5 TINY = 0 - PRE = 'beta11' + PRE = 'beta1' STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end From 5774107a2d8f5522d9f6bf612fa1baafa57ac7ed Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Thu, 27 Feb 2020 10:22:55 +0530 Subject: [PATCH 0005/1830] FIX: downloaded image URLs incorrectly replaced in post raw. (#9014) Previously, while replacing the downloaded image URL `http://wiki.mozilla.org/images/2/2e/Longcat1.png` similar non-image URL `http://wiki.mozilla.org/images/2` was replaced wrongly. --- app/jobs/regular/pull_hotlinked_images.rb | 2 +- spec/jobs/pull_hotlinked_images_spec.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/jobs/regular/pull_hotlinked_images.rb b/app/jobs/regular/pull_hotlinked_images.rb index 252c379052..2570365946 100644 --- a/app/jobs/regular/pull_hotlinked_images.rb +++ b/app/jobs/regular/pull_hotlinked_images.rb @@ -95,7 +95,7 @@ module Jobs escaped_src = Regexp.escape(original_src) replace_raw = ->(match, match_src, replacement, _index) { - if src.include?(match_src) + if remove_scheme(src) == remove_scheme(match_src) replacement = if replacement.include?(InlineUploads::PLACEHOLDER) diff --git a/spec/jobs/pull_hotlinked_images_spec.rb b/spec/jobs/pull_hotlinked_images_spec.rb index 4040674450..6e3a21ca9a 100644 --- a/spec/jobs/pull_hotlinked_images_spec.rb +++ b/spec/jobs/pull_hotlinked_images_spec.rb @@ -83,6 +83,17 @@ describe Jobs::PullHotlinkedImages do RAW end + it 'replaces correct image URL' do + url = image_url.sub("/2e/Longcat1.png", '') + post = Fabricate(:post, raw: "[Images](#{url})\n![](#{image_url})") + + expect do + Jobs::PullHotlinkedImages.new.execute(post_id: post.id) + end.to change { Upload.count }.by(1) + + expect(post.reload.raw).to eq("[Images](#{url})\n![](#{Upload.last.short_url})") + end + it 'replaces images without protocol' do url = image_url.sub(/^https?\:/, '') post = Fabricate(:post, raw: "test") From acf337d58300a7cca189fa49059902a7aa37ef55 Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Thu, 27 Feb 2020 11:09:37 +0530 Subject: [PATCH 0006/1830] FEATURE: auto archive group message if topic is closed. (#9046) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Régis Hanol --- app/models/topic.rb | 11 +++++++++++ spec/models/topic_spec.rb | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/app/models/topic.rb b/app/models/topic.rb index 44d02260ae..ff4b785708 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -502,6 +502,17 @@ class Topic < ActiveRecord::Base def update_status(status, enabled, user, opts = {}) TopicStatusUpdater.new(self, user).update!(status, enabled, opts) DiscourseEvent.trigger(:topic_status_updated, self, status, enabled) + + if enabled && private_message? && status.to_s["closed"] + group_ids = user.groups.pluck(:id) + if group_ids.present? + allowed_group_ids = self.allowed_groups + .where('topic_allowed_groups.group_id IN (?)', group_ids).pluck(:id) + allowed_group_ids.each do |id| + GroupArchivedMessage.archive!(id, self) + end + end + end end # Atomically creates the next post number diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 73bfdc330b..ec2956d660 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -1114,6 +1114,14 @@ describe Topic do context 'closed' do let(:status) { 'closed' } it_should_behave_like 'a status that closes a topic' + + it 'should archive group message' do + group = Fabricate(:group) + group.add(@user) + topic = Fabricate(:private_message_topic, allowed_groups: [group]) + + expect { topic.update_status(status, true, @user) }.to change(topic.group_archived_messages, :count).by(1) + end end context 'autoclosed' do From a4fc6ccc121ffb618a5054a63bcb6239812fd553 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 27 Feb 2020 11:09:54 +0100 Subject: [PATCH 0007/1830] UX: prevents jumpyness when displaying poll voters (#9054) --- plugins/poll/assets/stylesheets/common/poll.scss | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/poll/assets/stylesheets/common/poll.scss b/plugins/poll/assets/stylesheets/common/poll.scss index 4ab9e427ab..8306f7bfcf 100644 --- a/plugins/poll/assets/stylesheets/common/poll.scss +++ b/plugins/poll/assets/stylesheets/common/poll.scss @@ -67,7 +67,9 @@ div.poll { } .poll-voters:not(:empty) { + min-height: 30px; margin-bottom: 0.25em; + li { display: inline; } @@ -76,6 +78,10 @@ div.poll { .poll-voters-toggle-expand { width: 100%; text-align: center; + + .spinner { + margin-top: 0.25em; + } } .results { From dfe11321d83cf919bddf57ee23a67da2ff8729fb Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 27 Feb 2020 12:13:07 +0000 Subject: [PATCH 0008/1830] FIX: Polyfill Promise for IE11 (#9057) Co-authored-by: Joffrey JAFFEUX --- plugins/discourse-internet-explorer/public/js/ie.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/discourse-internet-explorer/public/js/ie.js b/plugins/discourse-internet-explorer/public/js/ie.js index 4c0fbf5fd8..6c998e402a 100644 --- a/plugins/discourse-internet-explorer/public/js/ie.js +++ b/plugins/discourse-internet-explorer/public/js/ie.js @@ -970,3 +970,12 @@ if (!String.prototype.startsWith) { return ES6; }); /* eslint-enable */ + +// Polyfill Promise - used by popper.js +window.addEventListener( + "load", + function() { + window.Promise = require("rsvp").Promise; + }, + false +); From 60908a94ece0e62e4ffb3fb619deb3e242079f67 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Thu, 27 Feb 2020 14:45:20 +0200 Subject: [PATCH 0009/1830] FIX: Skip 'invited' small action if user is in an invited group (#9056) Inviting a user that is already invited through a group used to generate a small action and a notification. This commit skips that small action. --- app/models/topic.rb | 4 +++- spec/models/topic_spec.rb | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/models/topic.rb b/app/models/topic.rb index ff4b785708..7947900b13 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -1441,7 +1441,9 @@ class Topic < ActiveRecord::Base Topic.transaction do rate_limit_topic_invitation(invited_by) topic_allowed_users.create!(user_id: target_user.id) unless topic_allowed_users.exists?(user_id: target_user.id) - add_small_action(invited_by, "invited_user", target_user.username) + + user_in_allowed_group = (user.group_ids & topic_allowed_groups.map(&:group_id)).present? + add_small_action(invited_by, "invited_user", target_user.username) if !user_in_allowed_group create_invite_notification!( target_user, diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index ec2956d660..e882c3fd05 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -618,6 +618,15 @@ describe Topic do expect(Post.last.action_code).to eq("removed_user") end + it 'should not create a small action if user is already invited through a group' do + group = Fabricate(:group, users: [user, another_user]) + expect(topic.invite_group(user, group)).to eq(true) + + expect { topic.invite(user, another_user.username) } + .to change { Notification.count }.by(1) + .and change { Post.where(post_type: Post.types[:small_action]).count }.by(0) + end + context "from a muted user" do before { MutedUser.create!(user: another_user, muted_user: user) } From 56345faf9a981403b06787526172c5f89362b751 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 27 Feb 2020 14:04:23 +0100 Subject: [PATCH 0010/1830] FIX: prevents row click event to be caught by filter input event (#9059) This was causing some dropdowns to not work under IE11 --- .../select-kit/components/select-kit/select-kit-filter.js.es6 | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 index 174f32fd6d..0c833d0a0c 100644 --- a/app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-filter.js.es6 @@ -43,6 +43,7 @@ export default Component.extend(UtilsMixin, { actions: { onInput(event) { this.selectKit.onInput(event); + return true; }, onKeydown(event) { From 0af2f5db6451187edcf4268655608385090a088f Mon Sep 17 00:00:00 2001 From: adam j hartz Date: Thu, 27 Feb 2020 08:25:32 -0500 Subject: [PATCH 0011/1830] UX: Differentiate Between PMs and Topics in Search Results (#8933) PMs will now display an envelope icon next to the topic title in search results. This is especially useful when searching using `in:all`. Co-authored-by: adam j hartz --- .../discourse/components/topic-status.js.es6 | 11 +++++++++++ .../discourse/templates/components/topic-status.hbs | 5 ++++- .../discourse/templates/full-page-search.hbs | 3 ++- app/assets/stylesheets/common/base/discourse.scss | 2 +- app/serializers/listable_topic_serializer.rb | 1 + config/locales/client.en.yml | 1 + 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/components/topic-status.js.es6 b/app/assets/javascripts/discourse/components/topic-status.js.es6 index ecd6f448de..569292eb5e 100644 --- a/app/assets/javascripts/discourse/components/topic-status.js.es6 +++ b/app/assets/javascripts/discourse/components/topic-status.js.es6 @@ -44,6 +44,17 @@ export default Component.extend({ : this._reset("warning"); }, + @discourseComputed( + "showPrivateMessageIcon", + "topic.isPrivateMessage", + "topic.is_warning" + ) + topicPrivateMessage(showPrivateMessageIcon, privateMessage, warning) { + return showPrivateMessageIcon && privateMessage && !warning + ? this._set("privateMessage", "envelope", "personal_message") + : this._reset("privateMessage"); + }, + @discourseComputed("topic.pinned") topicPinned(pinned) { return pinned diff --git a/app/assets/javascripts/discourse/templates/components/topic-status.hbs b/app/assets/javascripts/discourse/templates/components/topic-status.hbs index f21fbf151d..bf655d9219 100644 --- a/app/assets/javascripts/discourse/templates/components/topic-status.hbs +++ b/app/assets/javascripts/discourse/templates/components/topic-status.hbs @@ -7,8 +7,11 @@ {{~#if archivedIcon~}} {{archivedIcon}} {{~/if~}} +{{~#if topicPrivateMessage~}} + {{privateMessageIcon}} +{{~/if~}} {{~#if topicWarning~}} - {{warningIcon}} + {{warningIcon}} {{~/if~}} {{~#if topicPinned~}} {{~#if canAct~}} diff --git a/app/assets/javascripts/discourse/templates/full-page-search.hbs b/app/assets/javascripts/discourse/templates/full-page-search.hbs index 1317bbc753..7a2cbbd999 100644 --- a/app/assets/javascripts/discourse/templates/full-page-search.hbs +++ b/app/assets/javascripts/discourse/templates/full-page-search.hbs @@ -85,7 +85,8 @@ {{/if}} - {{topic-status topic=result.topic disableActions=true}}{{#highlight-text highlight=q}}{{{unbound result.topic.fancyTitle}}}{{/highlight-text}} + {{topic-status topic=result.topic disableActions=true showPrivateMessageIcon=true}} + {{#highlight-text highlight=q}}{{{unbound result.topic.fancyTitle}}}{{/highlight-text}}
diff --git a/app/assets/stylesheets/common/base/discourse.scss b/app/assets/stylesheets/common/base/discourse.scss index f8ea7b11cc..023154c7da 100644 --- a/app/assets/stylesheets/common/base/discourse.scss +++ b/app/assets/stylesheets/common/base/discourse.scss @@ -714,7 +714,7 @@ table { } } - .d-icon-envelope { + .topic-status-warning .d-icon-envelope { color: $danger; } } diff --git a/app/serializers/listable_topic_serializer.rb b/app/serializers/listable_topic_serializer.rb index 4e5829df02..8a169eb194 100644 --- a/app/serializers/listable_topic_serializer.rb +++ b/app/serializers/listable_topic_serializer.rb @@ -9,6 +9,7 @@ class ListableTopicSerializer < BasicTopicSerializer :last_posted_at, :bumped, :bumped_at, + :archetype, :unseen, :last_read_post_number, :unread, diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1211978b66..2253b4fe8e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2861,6 +2861,7 @@ en: help: "This topic is unlisted; it will not be displayed in topic lists, and can only be accessed via a direct link" personal_message: title: "This topic is a personal message" + help: "This topic is a personal message" posts: "Posts" posts_long: "there are {{number}} posts in this topic" From d4617726613346fa1db18594d501841dbc379211 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Thu, 27 Feb 2020 16:01:59 +0200 Subject: [PATCH 0012/1830] FIX: Skip poll tutorial if user cannot create polls (#9058) --- .../advanced_user_narrative.rb | 2 +- .../advanced_user_narrative_spec.rb | 23 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb index 8da5cdc059..185d472ea6 100644 --- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb +++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/advanced_user_narrative.rb @@ -82,7 +82,7 @@ module DiscourseNarrativeBot }, tutorial_poll: { - prerequisite: Proc.new { SiteSetting.poll_enabled }, + prerequisite: Proc.new { SiteSetting.poll_enabled && @user.has_trust_level?(SiteSetting.poll_minimum_trust_level_to_create) }, next_state: :tutorial_details, next_instructions: Proc.new { I18n.t("#{I18N_KEY}.details.instructions", i18n_post_args) }, reply: { diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb index d9ea4c9e2e..a44c9e250c 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb @@ -556,12 +556,29 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do end end - describe 'when poll is disabled' do - before do + describe 'when user cannot create polls' do + it 'should create the right reply (polls disabled)' do SiteSetting.poll_enabled = false + + TopicUser.change( + user.id, + topic.id, + notification_level: TopicUser.notification_levels[:tracking] + ) + + expected_raw = <<~RAW + #{I18n.t('discourse_narrative_bot.advanced_user_narrative.change_topic_notification_level.reply', base_uri: '')} + + #{I18n.t('discourse_narrative_bot.advanced_user_narrative.details.instructions', base_uri: '')} + RAW + + expect(Post.last.raw).to eq(expected_raw.chomp) + expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_details) end - it 'should create the right reply' do + it 'should create the right reply (insufficient trust level)' do + user.update(trust_level: 0) + TopicUser.change( user.id, topic.id, From 4673f31c75b3231815025cfb930cfb5cbfd16fc8 Mon Sep 17 00:00:00 2001 From: romanrizzi Date: Thu, 27 Feb 2020 11:07:46 -0300 Subject: [PATCH 0013/1830] FIX: Bulk badge awards should work even if the CSV has nil values --- app/controllers/admin/badges_controller.rb | 8 ++++++-- .../fixtures/csv/usernames_with_nil_values.csv | 4 ++++ spec/requests/admin/badges_controller_spec.rb | 18 ++++++++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 spec/fixtures/csv/usernames_with_nil_values.csv diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb index 2c1846d3da..e3aca683d6 100644 --- a/app/controllers/admin/badges_controller.rb +++ b/app/controllers/admin/badges_controller.rb @@ -55,8 +55,12 @@ class Admin::BadgesController < Admin::AdminController csv.rewind csv.each_line do |email_line| - batch.concat CSV.parse_line(email_line) - line_number += 1 + line = CSV.parse_line(email_line).first + + if line.present? + batch << line + line_number += 1 + end # Split the emails in batches of 200 elements. full_batch = csv.lineno % (BadgeGranter::MAX_ITEMS_FOR_DELTA * batch_number) == 0 diff --git a/spec/fixtures/csv/usernames_with_nil_values.csv b/spec/fixtures/csv/usernames_with_nil_values.csv new file mode 100644 index 0000000000..b35b163ca5 --- /dev/null +++ b/spec/fixtures/csv/usernames_with_nil_values.csv @@ -0,0 +1,4 @@ +username1, +username2, +username3, +,, diff --git a/spec/requests/admin/badges_controller_spec.rb b/spec/requests/admin/badges_controller_spec.rb index 06d294bcc0..f54875a21a 100644 --- a/spec/requests/admin/badges_controller_spec.rb +++ b/spec/requests/admin/badges_controller_spec.rb @@ -179,6 +179,8 @@ describe Admin::BadgesController do end describe '#mass_award' do + before { @user = Fabricate(:user, email: 'user1@test.com', username: 'username1') } + it 'does nothing when there is no file' do post "/admin/badges/award/#{badge.id}.json", params: { file: '' } @@ -202,23 +204,31 @@ describe Admin::BadgesController do it 'awards the badge using a list of user emails' do Jobs.run_immediately! - user = Fabricate(:user, email: 'user1@test.com') file = file_from_fixtures('user_emails.csv', 'csv') post "/admin/badges/award/#{badge.id}.json", params: { file: fixture_file_upload(file) } - expect(UserBadge.exists?(user: user, badge: badge)).to eq(true) + expect(UserBadge.exists?(user: @user, badge: badge)).to eq(true) end it 'awards the badge using a list of usernames' do Jobs.run_immediately! - user = Fabricate(:user, username: 'username1') file = file_from_fixtures('usernames.csv', 'csv') post "/admin/badges/award/#{badge.id}.json", params: { file: fixture_file_upload(file) } - expect(UserBadge.exists?(user: user, badge: badge)).to eq(true) + expect(UserBadge.exists?(user: @user, badge: badge)).to eq(true) + end + + it 'works with a CSV containing nil values' do + Jobs.run_immediately! + + file = file_from_fixtures('usernames_with_nil_values.csv', 'csv') + + post "/admin/badges/award/#{badge.id}.json", params: { file: fixture_file_upload(file) } + + expect(UserBadge.exists?(user: @user, badge: badge)).to eq(true) end end end From 501936f0da943d0d0d2fb24cdd634d64fbd459ba Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 27 Feb 2020 15:20:04 +0100 Subject: [PATCH 0014/1830] FIX: prevents loading to show during debouncing (#9060) This will also fix a bug in IE11 where click event would not be triggered on row --- app/assets/javascripts/select-kit/components/select-kit.js.es6 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/select-kit/components/select-kit.js.es6 b/app/assets/javascripts/select-kit/components/select-kit.js.es6 index 3159d596a9..ed78c9ed78 100644 --- a/app/assets/javascripts/select-kit/components/select-kit.js.es6 +++ b/app/assets/javascripts/select-kit/components/select-kit.js.es6 @@ -382,13 +382,12 @@ export default Component.extend( ); if (input) { - this.selectKit.set("isLoading", true); debounce(this, this._debouncedInput, event.target.value, 200); } }, _debouncedInput(filter) { - this.selectKit.set("filter", filter); + this.selectKit.setProperties({ filter, isLoading: true }); this._searchPromise = this._searchWrapper(filter); }, From 87f15f9ed65f0363344d56f701f2e511ee0e96a5 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Thu, 27 Feb 2020 14:10:14 -0300 Subject: [PATCH 0016/1830] FIX: When appending tags to restricted category posts, we need to pass the category id, or it won't work. (#9020) --- .../components/search-advanced-options.js.es6 | 11 ++++++++--- .../discourse/routes/full-page-search.js.es6 | 1 + .../discourse/templates/full-page-search.hbs | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 index 855fed4e28..eb61067167 100644 --- a/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 +++ b/app/assets/javascripts/discourse/components/search-advanced-options.js.es6 @@ -219,6 +219,11 @@ export default Component.extend({ } }, + setCategory(category) { + this.set("searchedTerms.category", category); + this.set("category", category); + }, + setSearchedTermValueForCategory() { const match = this.filterBlocks(REGEXP_CATEGORY_PREFIX); if (match.length !== 0) { @@ -235,21 +240,21 @@ export default Component.extend({ (!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id) ) - this.set("searchedTerms.category", userInput); + this.setCategory(userInput); } else if (isNaN(subcategories)) { const userInput = Category.findSingleBySlug(subcategories[0]); if ( (!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id) ) - this.set("searchedTerms.category", userInput); + this.setCategory(userInput); } else { const userInput = Category.findById(subcategories[0]); if ( (!existingInput && userInput) || (existingInput && userInput && existingInput.id !== userInput.id) ) - this.set("searchedTerms.category", userInput); + this.setCategory(userInput); } } else this.set("searchedTerms.category", ""); }, diff --git a/app/assets/javascripts/discourse/routes/full-page-search.js.es6 b/app/assets/javascripts/discourse/routes/full-page-search.js.es6 index ca7906e109..6fe75cd83b 100644 --- a/app/assets/javascripts/discourse/routes/full-page-search.js.es6 +++ b/app/assets/javascripts/discourse/routes/full-page-search.js.es6 @@ -17,6 +17,7 @@ export default DiscourseRoute.extend({ context: {}, skip_context: {} }, + category: null, titleToken() { return I18n.t("search.results_page", { diff --git a/app/assets/javascripts/discourse/templates/full-page-search.hbs b/app/assets/javascripts/discourse/templates/full-page-search.hbs index 7a2cbbd999..e903c5cd02 100644 --- a/app/assets/javascripts/discourse/templates/full-page-search.hbs +++ b/app/assets/javascripts/discourse/templates/full-page-search.hbs @@ -36,7 +36,7 @@ {{#if canBulkSelect}} {{d-button icon="list" class="btn-default bulk-select" title="topics.bulk.toggle" action=(action "toggleBulkSelect")}} - {{bulk-select-button selected=selected action=(action "search")}} + {{bulk-select-button selected=selected category=category action=(action "search")}} {{/if}} {{#if bulkSelectEnabled}} @@ -211,6 +211,7 @@ {{search-advanced-options searchTerm=searchTerm isExpanded=true + category=category }} {{d-button From 337b823ec6492e4a4614598bef38d8351153b0e2 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Thu, 27 Feb 2020 11:47:15 -0600 Subject: [PATCH 0017/1830] Merge pull request from GHSA-vw39-6w7q-gfx5 Co-authored-by: Robin Ward --- .../discourse/components/iframed-html.js.es6 | 19 +++++++++++++++ .../discourse/templates/modal/raw-email.hbs | 4 +--- app/assets/stylesheets/common/base/modal.scss | 6 +++++ .../common/components/iframed-html.scss | 4 ++++ .../components/iframed-html-test.js.es6 | 23 +++++++++++++++++++ 5 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/iframed-html.js.es6 create mode 100644 app/assets/stylesheets/common/components/iframed-html.scss create mode 100644 test/javascripts/components/iframed-html-test.js.es6 diff --git a/app/assets/javascripts/discourse/components/iframed-html.js.es6 b/app/assets/javascripts/discourse/components/iframed-html.js.es6 new file mode 100644 index 0000000000..a8c39e583e --- /dev/null +++ b/app/assets/javascripts/discourse/components/iframed-html.js.es6 @@ -0,0 +1,19 @@ +import Component from "@ember/component"; + +export default Component.extend({ + tagName: "iframe", + html: null, + className: "", + classNameBindings: ["html:iframed-html", "className"], + sandbox: "allow-same-origin", + attributeBindings: ['sandbox:sandbox'], + + didRender() { + this._super(...arguments); + const iframeDoc = this.element.contentWindow.document; + iframeDoc.open("text/html", "replace"); + iframeDoc.write(this.html); + iframeDoc.close(); + } +}); + diff --git a/app/assets/javascripts/discourse/templates/modal/raw-email.hbs b/app/assets/javascripts/discourse/templates/modal/raw-email.hbs index 489064f166..0a3a0eda22 100644 --- a/app/assets/javascripts/discourse/templates/modal/raw-email.hbs +++ b/app/assets/javascripts/discourse/templates/modal/raw-email.hbs @@ -37,9 +37,7 @@ {{/if}} {{#if showHtmlPart}} -
- {{{htmlPart}}} -
+ {{iframed-html html=htmlPart className="incoming-email-html-part"}} {{/if}}
{{/d-modal-body}} diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index f67a36cae6..e24acf027f 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -494,8 +494,14 @@ box-shadow: none; } .incoming-email-html-part { + width: calc(100% - 36px); padding: 10px 4px 4px 4px; } + @media screen and (max-width: 760px) { + .incoming-email-html-part { + width: calc(100% - 10px); + } + } } } diff --git a/app/assets/stylesheets/common/components/iframed-html.scss b/app/assets/stylesheets/common/components/iframed-html.scss new file mode 100644 index 0000000000..0b613852a1 --- /dev/null +++ b/app/assets/stylesheets/common/components/iframed-html.scss @@ -0,0 +1,4 @@ +.iframed-html { + background: white; + border: none; +} diff --git a/test/javascripts/components/iframed-html-test.js.es6 b/test/javascripts/components/iframed-html-test.js.es6 new file mode 100644 index 0000000000..ad7d4113f4 --- /dev/null +++ b/test/javascripts/components/iframed-html-test.js.es6 @@ -0,0 +1,23 @@ +import componentTest from "helpers/component-test"; + +moduleForComponent("iframed-html", { integration: true }); + +componentTest("appends the html into the iframe", { + template: `{{iframed-html html="

hello

" className='this-is-an-iframe'}}`, + + async test(assert) { + const iframe = find("iframe.this-is-an-iframe"); + assert.equal(iframe.length, 1, "inserts an iframe"); + + assert.ok( + iframe[0].classList.contains("this-is-an-iframe"), + "Adds className to the iframes classList" + ); + + assert.equal( + iframe[0].contentWindow.document.body.querySelectorAll("#find-me").length, + 1, + "inserts the passed in html into the iframe" + ); + } +}); From f3581143617ca998936e7ee1ffac26c9fde26439 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Thu, 27 Feb 2020 11:56:13 -0600 Subject: [PATCH 0018/1830] FIX: Prettier on iframed-html component (#9062) --- .../javascripts/discourse/components/iframed-html.js.es6 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/components/iframed-html.js.es6 b/app/assets/javascripts/discourse/components/iframed-html.js.es6 index a8c39e583e..f05b5d278b 100644 --- a/app/assets/javascripts/discourse/components/iframed-html.js.es6 +++ b/app/assets/javascripts/discourse/components/iframed-html.js.es6 @@ -6,7 +6,7 @@ export default Component.extend({ className: "", classNameBindings: ["html:iframed-html", "className"], sandbox: "allow-same-origin", - attributeBindings: ['sandbox:sandbox'], + attributeBindings: ["sandbox:sandbox"], didRender() { this._super(...arguments); @@ -16,4 +16,3 @@ export default Component.extend({ iframeDoc.close(); } }); - From 8e5edae0936b17e32139137b748763977f45c101 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Fri, 28 Feb 2020 09:20:36 +1100 Subject: [PATCH 0019/1830] FEATURE: unconditionally skip indexing on search controller There are absolutely no actions in search that need indexing Also no point adding this header on non get requests --- app/controllers/application_controller.rb | 2 +- app/controllers/search_controller.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c6cfcf3165..23872ed560 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -807,7 +807,7 @@ class ApplicationController < ActionController::Base end def add_noindex_header - response.headers['X-Robots-Tag'] = 'noindex' + response.headers['X-Robots-Tag'] = 'noindex' if request.get? end protected diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 3f0914e2dc..a2dd66ea5f 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -2,9 +2,9 @@ class SearchController < ApplicationController - skip_before_action :check_xhr, only: :show - before_action :cancel_overloaded_search, only: [:query] + skip_before_action :check_xhr, only: :show + after_action :add_noindex_header def self.valid_context_types %w{user topic category private_messages tag} From 14adddd18d8ad7ff6372cd1859d1b2ac01de51ba Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Fri, 28 Feb 2020 12:11:30 +1000 Subject: [PATCH 0020/1830] FIX: Ignore secure-media-uploads for miniprofiler (#9070) --- config/initializers/006-mini_profiler.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/initializers/006-mini_profiler.rb b/config/initializers/006-mini_profiler.rb index a717c48ae3..ce3443e051 100644 --- a/config/initializers/006-mini_profiler.rb +++ b/config/initializers/006-mini_profiler.rb @@ -41,6 +41,7 @@ if defined?(Rack::MiniProfiler) && defined?(Rack::MiniProfiler::Config) /^\/logs/, /^\/site_customizations/, /^\/uploads/, + /^\/secure-media-uploads/, /^\/javascripts\//, /^\/images\//, /^\/stylesheets\//, From 60184a290c45926583393cf53895e063b4798ff5 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Fri, 28 Feb 2020 11:10:03 +0200 Subject: [PATCH 0021/1830] FIX: Sync preload key format for category topic lists The server and client used two different formats for preload keys. The server was using 'topic_list_c/SLUG/l/latest', but the client was using 'topic_list_c/SLUG/ID/l/latest'. This commit is an addition to 374534f00ee487d859fc2b826ea519befe0da350. --- app/models/topic_list.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/topic_list.rb b/app/models/topic_list.rb index 52b0ee0070..d51c0f153f 100644 --- a/app/models/topic_list.rb +++ b/app/models/topic_list.rb @@ -67,7 +67,7 @@ class TopicList def preload_key if @category - "topic_list_#{@category.url.sub(/^\//, '')}/l/#{@filter}" + "topic_list_#{@category.url.sub(/^\//, '')}/#{@category.id}/l/#{@filter}" else "topic_list_#{@filter}" end From 8cbb6e35cbfc36d46223fadcf880dccc0f415cf8 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Fri, 28 Feb 2020 11:31:04 +0200 Subject: [PATCH 0022/1830] DEV: Fix build Follow up to 60184a290c45926583393cf53895e063b4798ff5. --- spec/components/topic_query_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index b4c5cd9345..3793da7579 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -145,7 +145,7 @@ describe TopicQuery do list = TopicQuery.new(moderator, category: diff_category.slug).list_latest expect(list.topics.size).to eq(1) - expect(list.preload_key).to eq("topic_list_c/different-category/l/latest") + expect(list.preload_key).to eq("topic_list_c/different-category/#{diff_category.id}/l/latest") # Defaults to no category filter when slug does not exist expect(TopicQuery.new(moderator, category: 'made up slug').list_latest.topics.size).to eq(2) From 0903aa44bb3c6060979be3ea0ceef5710f5a90e4 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 28 Feb 2020 10:53:11 +0000 Subject: [PATCH 0023/1830] FEATURE: Always disable customizations on the `/safe-mode` route (#9052) This makes it easier to enter safe mode when a customization has made the UI unusable --- app/controllers/safe_mode_controller.rb | 6 ++++++ spec/requests/safe_mode_controller_spec.rb | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/app/controllers/safe_mode_controller.rb b/app/controllers/safe_mode_controller.rb index 76a93ebf59..d0742eba10 100644 --- a/app/controllers/safe_mode_controller.rb +++ b/app/controllers/safe_mode_controller.rb @@ -3,6 +3,7 @@ class SafeModeController < ApplicationController layout 'no_ember' before_action :ensure_safe_mode_enabled + before_action :force_safe_mode_for_route skip_before_action :preload_json, :check_xhr @@ -29,4 +30,9 @@ class SafeModeController < ApplicationController raise Discourse::NotFound unless guardian.can_enable_safe_mode? end + def force_safe_mode_for_route + request.env[ApplicationController::NO_CUSTOM] = true + request.env[ApplicationController::NO_PLUGINS] = true + end + end diff --git a/spec/requests/safe_mode_controller_spec.rb b/spec/requests/safe_mode_controller_spec.rb index 542e3ed7d8..6bba0dad93 100644 --- a/spec/requests/safe_mode_controller_spec.rb +++ b/spec/requests/safe_mode_controller_spec.rb @@ -3,6 +3,18 @@ require 'rails_helper' RSpec.describe SafeModeController do + describe 'index' do + it 'never includes customizations' do + theme = Fabricate(:theme) + theme.set_field(target: :common, name: "header", value: "My Custom Header") + theme.save! + theme.set_default! + + get '/safe-mode' + expect(response.body).not_to include("My Custom Header") + end + end + describe 'enter' do context 'when no params are given' do it 'should redirect back to safe mode page' do From ff5ff8d0d27bd8482171399ece41182a8072fc33 Mon Sep 17 00:00:00 2001 From: Brad Morrical Date: Fri, 28 Feb 2020 09:26:18 -0600 Subject: [PATCH 0024/1830] fix invalid byte sequence in UTF-8 (ArgumentError) (#9077) --- script/import_scripts/simplepress.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/script/import_scripts/simplepress.rb b/script/import_scripts/simplepress.rb index 6932338009..3375258790 100644 --- a/script/import_scripts/simplepress.rb +++ b/script/import_scripts/simplepress.rb @@ -195,6 +195,11 @@ class ImportScripts::SimplePress < ImportScripts::Base def process_simplepress_post(raw, import_id) s = raw.dup + # fix invalid byte sequence in UTF-8 (ArgumentError) + unless s.valid_encoding? + s.force_encoding("UTF-8") + end + # convert the quote line s.gsub!(/\[quote='([^']+)'.*?pid='(\d+).*?\]/) { "[quote=\"#{convert_username($1, import_id)}, " + post_id_to_post_num_and_topic($2, import_id) + '"]' From 2db8ada22233419fd57a1f7a1cab076fa9762227 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 28 Feb 2020 17:58:22 +0100 Subject: [PATCH 0025/1830] FIX: ensures category url of category drop is built using slug and id (#9069) --- .../components/category-drop.js.es6 | 12 +++++------ .../select-kit/category-drop-test.js.es6 | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/select-kit/components/category-drop.js.es6 b/app/assets/javascripts/select-kit/components/category-drop.js.es6 index b5dcb7162a..5ee9a6d12b 100644 --- a/app/assets/javascripts/select-kit/components/category-drop.js.es6 +++ b/app/assets/javascripts/select-kit/components/category-drop.js.es6 @@ -155,18 +155,16 @@ export default ComboBoxComponent.extend({ }, actions: { - onChange(value) { + onChange(categoryId) { let categoryURL; - if (value === ALL_CATEGORIES_ID) { + if (categoryId === ALL_CATEGORIES_ID) { categoryURL = this.allCategoriesUrl; - } else if (value === NO_CATEGORIES_ID) { + } else if (categoryId === NO_CATEGORIES_ID) { categoryURL = this.noCategoriesUrl; } else { - const categoryId = parseInt(value, 10); - const category = Category.findById(categoryId); - const slug = Discourse.Category.slugFor(category); - categoryURL = `/c/${slug}`; + const category = Category.findById(parseInt(categoryId, 10)); + categoryURL = category.url; } DiscourseURL.routeToUrl(categoryURL); diff --git a/test/javascripts/components/select-kit/category-drop-test.js.es6 b/test/javascripts/components/select-kit/category-drop-test.js.es6 index e44b8d24a7..2a3b7b6e56 100644 --- a/test/javascripts/components/select-kit/category-drop-test.js.es6 +++ b/test/javascripts/components/select-kit/category-drop-test.js.es6 @@ -1,3 +1,4 @@ +import DiscourseURL from "discourse/lib/url"; import Category from "discourse/models/category"; import componentTest from "helpers/component-test"; import { testSelectKitModule } from "./select-kit-test-helper"; @@ -335,3 +336,22 @@ componentTest( } } ); + +componentTest("category url", { + template: template(), + + beforeEach() { + initCategoriesWithParentCategory(this); + sandbox.stub(DiscourseURL, "routeTo"); + }, + + async test(assert) { + await this.subject.expand(); + await this.subject.selectRowByValue(26); + + assert.ok( + DiscourseURL.routeTo.calledWith("/c/feature/spec/26"), + "it builds a correct URL" + ); + } +}); From 18ed2cc7d8224a32395ec92643856253dffd57ce Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2020 14:25:52 -0500 Subject: [PATCH 0026/1830] Build(deps): Bump puma from 4.3.1 to 4.3.2 (#9063) Bumps [puma](https://github.com/puma/puma) from 4.3.1 to 4.3.2. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.1...v4.3.2) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 56b4d03c26..8c8df3e761 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,7 +264,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.3) - puma (4.3.1) + puma (4.3.2) nio4r (~> 2.0) r2 (0.2.7) rack (2.0.8) From 18209e1dafe97e3c8f757e56de6ab2bbc03b0af3 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Sat, 29 Feb 2020 15:05:09 +1100 Subject: [PATCH 0027/1830] DEV: remove dead code This code is not called anywhere, remove it --- lib/topic_query.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 86c126f2fe..bfb787ce9f 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -19,12 +19,6 @@ class TopicQuery int.call(x) && x.to_i.between?(0, PG_MAX_INT) end - array_int_or_int = lambda do |x| - int.call(x) || ( - Array === x && x.length > 0 && x.all?(&int) - ) - end - { max_posts: zero_up_to_max_int, min_posts: zero_up_to_max_int, From b4999acadd3783e0953f04729cafc2fe0598db87 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Sat, 29 Feb 2020 15:40:54 +1100 Subject: [PATCH 0028/1830] PERF: improve performance of category topic list In some cases CTE caused pathologically bad query plans. This optimises it so query runs by itself and caches for lifetime of the topic query object. This lightweight caching is done cause topic query will often execute two queries (one for pinned and one for non pinned) --- lib/topic_query.rb | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/topic_query.rb b/lib/topic_query.rb index bfb787ce9f..f77d37e746 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -669,20 +669,11 @@ class TopicQuery if options[:no_subcategories] result = result.where('categories.id = ?', category_id) else - sql = <<~SQL - categories.id IN ( - WITH RECURSIVE subcategories AS ( - SELECT :category_id id, 1 depth - UNION - SELECT categories.id, (subcategories.depth + 1) depth - FROM categories - JOIN subcategories ON subcategories.id = categories.parent_category_id - WHERE subcategories.depth < :max_category_nesting - ) - SELECT subcategories.id FROM subcategories - ) AND (categories.id = :category_id OR topics.id != categories.topic_id) + result = result.where(<<~SQL, subcategory_ids: subcategory_ids(category_id), category_id: category_id) + categories.id in (:subcategory_ids) AND ( + categories.topic_id <> topics.id OR categories.id = :category_id + ) SQL - result = result.where(sql, category_id: category_id, max_category_nesting: SiteSetting.max_category_nesting) end result = result.references(:categories) @@ -1061,6 +1052,29 @@ class TopicQuery private + def subcategory_ids(category_id) + @subcategory_ids ||= {} + @subcategory_ids[category_id] ||= + begin + sql = <<~SQL + WITH RECURSIVE subcategories AS ( + SELECT :category_id id, 1 depth + UNION + SELECT categories.id, (subcategories.depth + 1) depth + FROM categories + JOIN subcategories ON subcategories.id = categories.parent_category_id + WHERE subcategories.depth < :max_category_nesting + ) + SELECT id FROM subcategories + SQL + DB.query_single( + sql, + category_id: category_id, + max_category_nesting: SiteSetting.max_category_nesting + ) + end + end + def sanitize_sql_array(input) ActiveRecord::Base.public_send(:sanitize_sql_array, input.join(',')) end From e23e247dffdc9e4b8dc840aa26369d82282435ef Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Sat, 29 Feb 2020 18:30:08 +1100 Subject: [PATCH 0029/1830] DEV: spec suite fails on leap years Something about year math fails here on leap years, just set up the clock so it is consistent to avoid it. --- spec/components/post_creator_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 779c829ed4..d5bbb9fef5 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -485,7 +485,8 @@ describe PostCreator do it 'whispers do not mess up the public view' do - freeze_time + # turns out this can fail on leap years if we don't do this + freeze_time DateTime.parse('2010-01-01 12:00') first = PostCreator.new( user, @@ -1414,7 +1415,7 @@ describe PostCreator do end it "links post uploads" do - public_post = PostCreator.create( + _public_post = PostCreator.create( user, topic_id: public_topic.id, raw: "A public post with an image.\n![](#{image_upload.short_path})" From 4635be10c88cb53779a12eb83daa38bf8101b799 Mon Sep 17 00:00:00 2001 From: Kane York Date: Sat, 29 Feb 2020 17:01:45 -0800 Subject: [PATCH 0030/1830] DEV: Add docker cleanup script to d/ folder --- bin/docker/cleanup | 3 +++ 1 file changed, 3 insertions(+) create mode 100755 bin/docker/cleanup diff --git a/bin/docker/cleanup b/bin/docker/cleanup new file mode 100755 index 0000000000..299b569ed4 --- /dev/null +++ b/bin/docker/cleanup @@ -0,0 +1,3 @@ +#!/bin/bash +docker container prune --filter until=1h +docker image prune --all --filter until=1h From 8123538c9495e80a5e208d89df3ec668a21e75b8 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Mon, 2 Mar 2020 15:40:29 +1000 Subject: [PATCH 0031/1830] DEV: Minor review fixes and fix bookmark spec logging (#9045) As per: https://review.discourse.org/t/fix-never-allow-custom-emoji-to-be-marked-secure-8965/9072 https://review.discourse.org/t/feature-improving-bookmarks-part-2-topic-bookmarking-8954/9038 --- app/models/post.rb | 4 ++-- spec/tasks/bookmarks_spec.rb | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index c0d69eac99..7e56dfa66b 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -918,8 +918,8 @@ class Post < ActiveRecord::Base if SiteSetting.secure_media? Upload.where( id: upload_ids, access_control_post_id: nil - ).where.not( - id: CustomEmoji.pluck(:upload_id) + ).where( + 'id NOT IN (SELECT upload_id FROM custom_emojis)' ).update_all( access_control_post_id: self.id ) diff --git a/spec/tasks/bookmarks_spec.rb b/spec/tasks/bookmarks_spec.rb index 16fea02f98..68f8588e0b 100644 --- a/spec/tasks/bookmarks_spec.rb +++ b/spec/tasks/bookmarks_spec.rb @@ -17,8 +17,14 @@ RSpec.describe "bookmarks tasks" do create_post_actions_and_existing_bookmarks end + def invoke_task(args = nil) + capture_stdout do + Rake::Task['bookmarks:sync_to_table'].invoke(args) + end + end + it "migrates all PostActions" do - Rake::Task['bookmarks:sync_to_table'].invoke + invoke_task expect(Bookmark.all.count).to eq(3) end @@ -26,14 +32,14 @@ RSpec.describe "bookmarks tasks" do it "does not create bookmarks that already exist in the bookmarks table for a user" do Fabricate(:bookmark, user: user1, post: post1) - Rake::Task['bookmarks:sync_to_table'].invoke + invoke_task expect(Bookmark.all.count).to eq(3) expect(Bookmark.where(post: post1, user: user1).count).to eq(1) end it "respects the sync_limit if provided and stops creating bookmarks at the limit (so this can be run progrssively" do - Rake::Task['bookmarks:sync_to_table'].invoke(1) + invoke_task(1) expect(Bookmark.all.count).to eq(1) end From 34fddaa824565a85cea78f923ad2f0c8471053b2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 10:34:17 +0000 Subject: [PATCH 0032/1830] Build(deps): Bump rails_multisite from 2.0.7 to 2.1.0 (#9083) Bumps [rails_multisite]() from 2.0.7 to 2.1.0. Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8c8df3e761..892b8cdf93 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -279,9 +279,9 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - rails_multisite (2.0.7) - activerecord (> 4.2, < 7) - railties (> 4.2, < 7) + rails_multisite (2.1.0) + activerecord (> 5.0, < 7) + railties (> 5.0, < 7) railties (6.0.1) actionpack (= 6.0.1) activesupport (= 6.0.1) From 68c7699c46214fe8dcefa72fad12376865f796c4 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Mon, 2 Mar 2020 13:34:00 +0000 Subject: [PATCH 0033/1830] Revert "Build(deps-dev): Bump annotate from 3.0.3 to 3.1.0 (#9013)" v3.1.0 has a bug which rewrites default annotations with erroneous quotes. https://github.com/ctran/annotate_models/issues/762 This reverts commit dd4a04e72c5bb9c37cdc44b588a76818628b524e. --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 892b8cdf93..95428727ea 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,7 +40,7 @@ GEM zeitwerk (~> 2.2) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - annotate (3.1.0) + annotate (3.0.3) activerecord (>= 3.2, < 7.0) rake (>= 10.4, < 14.0) ast (2.4.0) From 58f16f2e2b5eb3903f6fe85dc2c8b454872fd39e Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Mon, 2 Mar 2020 12:56:37 -0300 Subject: [PATCH 0034/1830] FIX: Make FooterNav work with PWAs on iPadOS --- app/assets/javascripts/discourse/lib/utilities.js.es6 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6 index ce91d7c8dc..3f24485fea 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js.es6 +++ b/app/assets/javascripts/discourse/lib/utilities.js.es6 @@ -367,9 +367,10 @@ export function areCookiesEnabled() { } export function isiOSPWA() { + const caps = Discourse.__container__.lookup("capabilities:main"); return ( window.matchMedia("(display-mode: standalone)").matches && - navigator.userAgent.match(/(iPad|iPhone|iPod)/g) + caps.isIOS ); } From fd38ed3631341379f40f9efd465b62088e4f56d6 Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Mon, 2 Mar 2020 13:04:52 -0300 Subject: [PATCH 0035/1830] DEV: Fix lint error introduced in 58f16f2 --- app/assets/javascripts/discourse/lib/utilities.js.es6 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6 index 3f24485fea..8b210b4737 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js.es6 +++ b/app/assets/javascripts/discourse/lib/utilities.js.es6 @@ -368,10 +368,7 @@ export function areCookiesEnabled() { export function isiOSPWA() { const caps = Discourse.__container__.lookup("capabilities:main"); - return ( - window.matchMedia("(display-mode: standalone)").matches && - caps.isIOS - ); + return window.matchMedia("(display-mode: standalone)").matches && caps.isIOS; } export function isAppWebview() { From d7ccb58559767a089d3aa3847bd74560762dc261 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Mon, 2 Mar 2020 17:24:48 +0100 Subject: [PATCH 0036/1830] FIX: Google Groups scraper failed to login --- script/import_scripts/google_groups.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/script/import_scripts/google_groups.rb b/script/import_scripts/google_groups.rb index 6e3f2f0969..d8f58cf323 100755 --- a/script/import_scripts/google_groups.rb +++ b/script/import_scripts/google_groups.rb @@ -158,12 +158,11 @@ def login get("https://google.com/404") add_cookies( - "accounts.google.com", "myaccount.google.com", "google.com" ) - get("https://accounts.google.com/servicelogin") + get("https://myaccount.google.com/?utm_source=sign_in_no_continue") begin wait_for_url { |url| url.start_with?("https://myaccount.google.com") } From 5889309d3b7b53bd358937641739956412530487 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Mon, 2 Mar 2020 17:44:01 +0100 Subject: [PATCH 0037/1830] FIX: Restoring with `disable_emails: false` didn't work anymore --- lib/backup_restore.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/backup_restore.rb b/lib/backup_restore.rb index 6259044dcb..4775fdd612 100644 --- a/lib/backup_restore.rb +++ b/lib/backup_restore.rb @@ -23,7 +23,8 @@ module BackupRestore factory: BackupRestore::Factory.new( user_id: user_id, client_id: opts[:client_id] - ) + ), + disable_emails: opts.fetch(:disable_emails, true) ) start! restorer From d05142d3f7e43b3328d2b0fb75178c6dbd548c9d Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Mon, 2 Mar 2020 13:27:38 -0300 Subject: [PATCH 0038/1830] FEATURE: Enable service worker on iOS PWA --- .../discourse/initializers/register-service-worker.js.es6 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/initializers/register-service-worker.js.es6 b/app/assets/javascripts/discourse/initializers/register-service-worker.js.es6 index c0099d7f30..fbfc4484de 100644 --- a/app/assets/javascripts/discourse/initializers/register-service-worker.js.es6 +++ b/app/assets/javascripts/discourse/initializers/register-service-worker.js.es6 @@ -10,9 +10,12 @@ export default { if (isSupported) { const caps = Discourse.__container__.lookup("capabilities:main"); - const isApple = caps.isSafari || caps.isIOS || caps.isIpadOS; + const isAppleBrowser = + caps.isSafari || + (caps.isIOS && + !window.matchMedia("(display-mode: standalone)").matches); - if (Discourse.ServiceWorkerURL && !isApple) { + if (Discourse.ServiceWorkerURL && !isAppleBrowser) { navigator.serviceWorker.getRegistrations().then(registrations => { for (let registration of registrations) { if ( From ed85cfe1419f785c6ca7514385e58f157808deb8 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Mon, 2 Mar 2020 20:06:02 +0100 Subject: [PATCH 0039/1830] FIX: prevents click on sk header to bubble (#9084) --- .../select-kit/select-kit-header.js.es6 | 1 + .../select-kit/single-select-test.js.es6 | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 b/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 index faf8f27b7e..6ec3984a98 100644 --- a/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 +++ b/app/assets/javascripts/select-kit/components/select-kit/select-kit-header.js.es6 @@ -13,6 +13,7 @@ export default Component.extend(UtilsMixin, { return; if (this.eventType !== "click" || event.button !== 0) return; this.selectKit.toggle(event); + return false; }, classNames: ["select-kit-header"], diff --git a/test/javascripts/components/select-kit/single-select-test.js.es6 b/test/javascripts/components/select-kit/single-select-test.js.es6 index 42f058a586..88dbbacf9e 100644 --- a/test/javascripts/components/select-kit/single-select-test.js.es6 +++ b/test/javascripts/components/select-kit/single-select-test.js.es6 @@ -238,3 +238,22 @@ componentTest("selected value can be 0", { assert.equal(this.subject.header().value(), 0); } }); + +componentTest("prevents propagating click event on header", { + template: + "{{#d-button icon='times' action=onClick}}{{single-select value=value content=content}}{{/d-button}}", + + beforeEach() { + this.setProperties({ + onClick: () => this.set("value", "foo"), + content: DEFAULT_CONTENT, + value: DEFAULT_VALUE + }); + }, + + async test(assert) { + assert.equal(this.value, DEFAULT_VALUE); + await this.subject.expand(); + assert.equal(this.value, DEFAULT_VALUE); + } +}); From d85726a866de8b40d5ddc57928addf1be1e2c4ea Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 14:09:05 -0500 Subject: [PATCH 0040/1830] Build(deps-dev): Bump simplecov from 0.18.3 to 0.18.5 (#9044) Bumps [simplecov](https://github.com/colszowka/simplecov) from 0.18.3 to 0.18.5. - [Release notes](https://github.com/colszowka/simplecov/releases) - [Changelog](https://github.com/colszowka/simplecov/blob/master/CHANGELOG.md) - [Commits](https://github.com/colszowka/simplecov/compare/v0.18.3...v0.18.5) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 95428727ea..e344103355 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -379,10 +379,10 @@ GEM rack (~> 2.0) rack-protection (>= 2.0.0) redis (>= 4.1.0) - simplecov (0.18.3) + simplecov (0.18.5) docile (~> 1.1) simplecov-html (~> 0.11) - simplecov-html (0.12.1) + simplecov-html (0.12.2) sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) From 98d4b7bbc1d3300819248c63c9bbe35edfce0b94 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 14:09:33 -0500 Subject: [PATCH 0041/1830] Build(deps-dev): Bump better_errors from 2.5.1 to 2.6.0 (#9043) Bumps [better_errors](https://github.com/BetterErrors/better_errors) from 2.5.1 to 2.6.0. - [Release notes](https://github.com/BetterErrors/better_errors/releases) - [Commits](https://github.com/BetterErrors/better_errors/compare/v2.5.1...v2.6.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index e344103355..e406cbd262 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,7 +66,7 @@ GEM barber (0.12.2) ember-source (>= 1.0, < 3.1) execjs (>= 1.2, < 3) - better_errors (2.5.1) + better_errors (2.6.0) coderay (>= 1.0.0) erubi (>= 1.0.0) rack (>= 0.9.0) From 93b8d7ec89cc86996dedd5438381f99712f58445 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 14:09:56 -0500 Subject: [PATCH 0042/1830] Build(deps): Bump puma from 4.3.2 to 4.3.3 (#9079) Bumps [puma](https://github.com/puma/puma) from 4.3.2 to 4.3.3. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.2...v4.3.3) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index e406cbd262..cd20b13fd1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -264,7 +264,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.3) - puma (4.3.2) + puma (4.3.3) nio4r (~> 2.0) r2 (0.2.7) rack (2.0.8) From 8e7868b4051376f7849dae5aa043d7636803cf9a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 14:10:19 -0500 Subject: [PATCH 0043/1830] Build(deps-dev): Bump rubocop from 0.80.0 to 0.80.1 (#9081) Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.80.0 to 0.80.1. - [Release notes](https://github.com/rubocop-hq/rubocop/releases) - [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.80.0...v0.80.1) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index cd20b13fd1..18d6188199 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -252,7 +252,7 @@ GEM parallel (1.19.1) parallel_tests (2.31.0) parallel - parser (2.7.0.2) + parser (2.7.0.4) ast (~> 2.4.0) pg (1.2.2) progress (3.5.2) @@ -339,7 +339,7 @@ GEM rspec-support (~> 3.8) rspec-support (3.9.2) rtlit (0.0.5) - rubocop (0.80.0) + rubocop (0.80.1) jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.7.0.1) From 5c39e21c1826d1d7e71ca188a9517cc99e1c0164 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Mon, 2 Mar 2020 20:20:37 +0100 Subject: [PATCH 0044/1830] UX: Allow correct pluralization for "too few topics and posts" notices (#8947) --- .../components/create-topics-notice.js.es6 | 10 +++++----- config/locales/client.en.yml | 19 ++++++++++++++++--- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 b/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 index 5622cfab94..7789ccd2bc 100644 --- a/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 +++ b/app/assets/javascripts/discourse/components/create-topics-notice.js.es6 @@ -68,21 +68,21 @@ export default Component.extend({ "topicTrackingState.incomingCount" ) message() { - var msg = null; + let msg = null; if ( this.publicTopicCount < this.requiredTopics && this.publicPostCount < this.requiredPosts ) { - msg = "too_few_topics_and_posts_notice"; + msg = "too_few_topics_and_posts_notice_MF"; } else if (this.publicTopicCount < this.requiredTopics) { - msg = "too_few_topics_notice"; + msg = "too_few_topics_notice_MF"; } else { - msg = "too_few_posts_notice"; + msg = "too_few_posts_notice_MF"; } return new Handlebars.SafeString( - I18n.t(msg, { + I18n.messageFormat(msg, { requiredTopics: this.requiredTopics, requiredPosts: this.requiredPosts, currentTopics: this.publicTopicCount, diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2253b4fe8e..127c964d04 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1372,9 +1372,22 @@ en: enabled: "This site is in read only mode. Please continue to browse, but replying, likes, and other actions are disabled for now." login_disabled: "Login is disabled while the site is in read only mode." logout_disabled: "Logout is disabled while the site is in read only mode." - too_few_topics_and_posts_notice: "Let's start the discussion! There are %{currentTopics} topics and %{currentPosts} posts. Visitors need more to read and reply to – we recommend at least %{requiredTopics} topics and %{requiredPosts} posts. Only staff can see this message." - too_few_topics_notice: "Let's start the discussion! There are %{currentTopics} topics. Visitors need more to read and reply to – we recommend at least %{requiredTopics} topics. Only staff can see this message." - too_few_posts_notice: "Let's start the discussion! There are %{currentPosts} posts. Visitors need more to read and reply to – we recommend at least %{requiredPosts} posts. Only staff can see this message." + too_few_topics_and_posts_notice_MF: >- + Let's start the discussion! + There {currentTopics, plural, one {is # topic} other {are # topics}} and + {currentPosts, plural, one {# post} other {# posts}}. Visitors need more to + read and reply to – we recommend at least {requiredTopics, plural, one {# topic} other {# topics}} + and {requiredPosts, plural, one {# post} other {# posts}}. Only staff can see this message. + too_few_topics_notice_MF: >- + Let's start the discussion! + There {currentTopics, plural, one {is # topic} other {are # topics}}. Visitors need more to + read and reply to – we recommend at least {requiredTopics, plural, one {# topic} other {# topics}}. + Only staff can see this message. + too_few_posts_notice_MF: >- + Let's start the discussion! + There {currentPosts, plural, one {is # post} other {are # posts}}. Visitors need more to + read and reply to – we recommend at least {requiredPosts, plural, one {# post} other {# posts}}. + Only staff can see this message. logs_error_rate_notice: # keys ending with _MF use message format, see https://meta.discourse.org/t/message-format-support-for-localization/7035 for details reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} other {# errors/hour}} reached site setting limit of {limit, plural, one {# error/hour} other {# errors/hour}}." From a09e5d12c23f2372c292e9b8cede4a63ddc8b0f0 Mon Sep 17 00:00:00 2001 From: tshenry Date: Mon, 2 Mar 2020 11:21:35 -0800 Subject: [PATCH 0045/1830] FIX: Topics should honor auto-close when published to category (#8963) * FIX: Topics should honor auto-close when published to category * Add test --- app/jobs/regular/publish_topic_to_category.rb | 2 ++ spec/jobs/publish_topic_to_category_spec.rb | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/app/jobs/regular/publish_topic_to_category.rb b/app/jobs/regular/publish_topic_to_category.rb index 1b86fc9034..79df028007 100644 --- a/app/jobs/regular/publish_topic_to_category.rb +++ b/app/jobs/regular/publish_topic_to_category.rb @@ -12,6 +12,8 @@ module Jobs TopicTimer.transaction do TopicPublisher.new(topic, Discourse.system_user, topic_timer.category_id).publish! end + + Topic.find(topic.id).inherit_auto_close_from_category end end end diff --git a/spec/jobs/publish_topic_to_category_spec.rb b/spec/jobs/publish_topic_to_category_spec.rb index 4b9a526b12..3602eaa5b3 100644 --- a/spec/jobs/publish_topic_to_category_spec.rb +++ b/spec/jobs/publish_topic_to_category_spec.rb @@ -84,4 +84,22 @@ RSpec.describe Jobs::PublishTopicToCategory do expect(message.data[:refresh_stream]).to be_present end end + + describe 'when new category has a default auto-close' do + before do + another_category.update!(auto_close_hours: 5) + end + + it 'should apply the auto-close timer upon publishing' do + topic + + described_class.new.execute(topic_timer_id: topic.public_topic_timer.id) + + topic.reload + topic_timer = topic.public_topic_timer + expect(topic.category).to eq(another_category) + expect(topic_timer.status_type).to eq(TopicTimer.types[:close]) + expect(topic_timer.execute_at).to be_within(1.second).of(5.hours.from_now) + end + end end From f9cc3dc4b7717d6dc40369742ef7cec1f918949a Mon Sep 17 00:00:00 2001 From: David Taylor Date: Mon, 2 Mar 2020 19:22:49 +0000 Subject: [PATCH 0046/1830] PERF: Allow passing an existing list of user field ids when loading (#8970) * PERF: Allow passing an existing list of user field ids when loading This avoids the need for running `UserField.pluck(:id)` for each user that is serialized * Memoize user_fields to avoid rebuilding hash ever time --- app/models/user.rb | 22 +++++++++++++--------- app/serializers/user_card_serializer.rb | 4 ++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index c4aa017b8d..e8cc35f891 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -475,7 +475,7 @@ class User < ActiveRecord::Base @unread_notifications = nil @unread_total_notifications = nil @unread_pms = nil - @user_fields = nil + @user_fields_cache = nil @ignored_user_ids = nil @muted_user_ids = nil super @@ -1093,16 +1093,20 @@ class User < ActiveRecord::Base USER_FIELD_PREFIX ||= "user_field_" - def user_fields - return @user_fields if @user_fields - user_field_ids = UserField.pluck(:id) - if user_field_ids.present? - @user_fields = {} - user_field_ids.each do |fid| - @user_fields[fid.to_s] = custom_fields["#{USER_FIELD_PREFIX}#{fid}"] + def user_fields(field_ids = nil) + if field_ids.nil? + field_ids = (@all_user_field_ids ||= UserField.pluck(:id)) + end + + @user_fields_cache ||= {} + + # Memoize based on requested fields + @user_fields_cache[field_ids.join(':')] ||= {}.tap do |hash| + field_ids.each do |fid| + # The hash keys are strings for backwards compatibility + hash[fid.to_s] = custom_fields["#{USER_FIELD_PREFIX}#{fid}"] end end - @user_fields end def number_of_deleted_posts diff --git a/app/serializers/user_card_serializer.rb b/app/serializers/user_card_serializer.rb index a689fc5957..5d53a6258c 100644 --- a/app/serializers/user_card_serializer.rb +++ b/app/serializers/user_card_serializer.rb @@ -140,8 +140,8 @@ class UserCardSerializer < BasicUserSerializer end def user_fields - allowed_keys = scope.allowed_user_field_ids(object).map(&:to_s) - object.user_fields&.select { |k, v| allowed_keys.include?(k) } + allowed_keys = scope.allowed_user_field_ids(object) + object.user_fields(allowed_keys) end def include_user_fields? From 76a06dfa038cb1f6bd7797d9514c824b4359b611 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Mon, 2 Mar 2020 20:23:46 +0100 Subject: [PATCH 0047/1830] DEV: Remove the last (defunct) use of Ember.View (#8976) This codepath has been deprecated 3 years ago in c5687100b04662b3d754ed0a8ae053d6298fca26. Ember.View has been removed in Ember 2.0. --- .../discourse/widgets/connector.js.es6 | 33 ++----------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/app/assets/javascripts/discourse/widgets/connector.js.es6 b/app/assets/javascripts/discourse/widgets/connector.js.es6 index 9701f4c80a..99b8053881 100644 --- a/app/assets/javascripts/discourse/widgets/connector.js.es6 +++ b/app/assets/javascripts/discourse/widgets/connector.js.es6 @@ -1,5 +1,4 @@ import { next } from "@ember/runloop"; -import deprecated from "discourse-common/lib/deprecated"; import { setOwner, getOwner } from "@ember/application"; export default class Connector { @@ -16,44 +15,18 @@ export default class Connector { next(() => { const mounted = widget._findView(); - if (opts.templateName) { - deprecated( - `Using a 'templateName' for a connector is deprecated. Use 'component' instead [${opts.templateName}]` - ); - } - - const container = getOwner ? getOwner(mounted) : mounted.container; - - let view; - if (opts.component) { const connector = widget.register.lookupFactory( "component:connector-container" ); - view = connector.create({ + + const view = connector.create({ layoutName: `components/${opts.component}`, model: widget.findAncestorModel() }); - } - if (opts.templateName) { - let context; - if (opts.context === "model") { - const model = widget.findAncestorModel(); - context = model; - } + setOwner(view, getOwner(mounted)); - view = Ember.View.create({ - container: container || widget.register, - templateName: opts.templateName, - context - }); - } - - if (view) { - if (setOwner) { - setOwner(view, getOwner(mounted)); - } mounted._connected.push(view); view.renderer.appendTo(view, $elem[0]); } From fedd8e3e3a1b45eb15e83908e5deb65251cbcb8e Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Mon, 2 Mar 2020 20:24:05 +0100 Subject: [PATCH 0048/1830] DEV: Remove uses of deprecated `Ember.copy` and `Copyable` (#8978) --- .../admin/controllers/admin-customize-colors-show.js.es6 | 2 +- .../javascripts/admin/controllers/admin-customize-colors.js.es6 | 2 +- app/assets/javascripts/admin/models/color-scheme.js.es6 | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 index 9cdca3f098..a27022390f 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-colors-show.js.es6 @@ -53,7 +53,7 @@ export default Controller.extend({ }, copy() { - var newColorScheme = Ember.copy(this.model, true); + const newColorScheme = this.model.copy(); newColorScheme.set( "name", I18n.t("admin.customize.colors.copy_name_prefix") + diff --git a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 index 869918bebb..e2ff119aa4 100644 --- a/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-customize-colors.js.es6 @@ -26,7 +26,7 @@ export default Controller.extend({ actions: { newColorSchemeWithBase(baseKey) { const base = this.baseColorSchemes.findBy("base_scheme_id", baseKey); - const newColorScheme = Ember.copy(base, true); + const newColorScheme = base.copy(); newColorScheme.setProperties({ name: I18n.t("admin.customize.colors.new_name"), base_scheme_id: base.get("base_scheme_id") diff --git a/app/assets/javascripts/admin/models/color-scheme.js.es6 b/app/assets/javascripts/admin/models/color-scheme.js.es6 index 8486002386..afabb1ed6e 100644 --- a/app/assets/javascripts/admin/models/color-scheme.js.es6 +++ b/app/assets/javascripts/admin/models/color-scheme.js.es6 @@ -4,7 +4,7 @@ import { ajax } from "discourse/lib/ajax"; import ColorSchemeColor from "admin/models/color-scheme-color"; import EmberObject from "@ember/object"; -const ColorScheme = EmberObject.extend(Ember.Copyable, { +const ColorScheme = EmberObject.extend({ init() { this._super(...arguments); From 176aa0ac7db32eefb6a4656f97cef9a23c44323c Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Mon, 2 Mar 2020 13:24:31 -0600 Subject: [PATCH 0049/1830] DEV: Import pretender instead of global server var (#8996) * DEV: Remove server global test variable * Delete yarn-error.log * prettier and some eslint fixes * add global server variable back for plugins * rename imported server to pretender * prettier * support plugin server. usage * Export pretender as named * Prettier * change default pretender export * fix bad import * Use pretender() and original default export * export new Pretender as default * fix accidental change * WIP testing * add pretend handlers in correct location * move more stuff into the correct pretender * Consolidated more pretenders * comment out another bad test * fix user acceptance tests * commented out bad test * fixed another composer server stub * fix more tests * fixed tag test pretender * Fix admin email test * removed another draft handler * add back test * fix and uncomment another test * remove test that is not useful * remove commented out lines * reapply handlers between every test * no need to re-stub requests now :) * cleanup from review * more cleanup --- .../acceptance/admin-emails-test.js.es6 | 6 +- .../acceptance/admin-user-emails-test.js.es6 | 62 +- .../acceptance/admin-user-index-test.js.es6 | 8 +- .../acceptance/click-track-test.js.es6 | 4 +- .../acceptance/composer-actions-test.js.es6 | 23 +- .../composer-edit-conflict-test.js.es6 | 44 +- .../acceptance/composer-test.js.es6 | 50 +- .../composer-uncategorized-test.js.es6 | 8 - test/javascripts/acceptance/group-test.js.es6 | 175 +- .../acceptance/keyboard-shortcuts-test.js.es6 | 10 +- ...l-and-hide-email-address-taken-test.js.es6 | 4 +- test/javascripts/acceptance/tags-test.js.es6 | 55 +- test/javascripts/acceptance/user-test.js.es6 | 20 +- .../components/admin-report-test.js.es6 | 20 +- .../components/badge-title-test.js.es6 | 4 +- .../select-kit/tag-drop-test.js.es6 | 14 +- .../select-kit/user-chooser-test.js.es6 | 6 +- .../javascripts/controllers/topic-test.js.es6 | 4 +- test/javascripts/fixtures/draft.js.es6 | 15 + .../helpers/create-pretender.js.es6 | 1444 +++++++++-------- .../lib/click-track-edit-history-test.js.es6 | 10 +- .../lib/click-track-profile-page-test.js.es6 | 10 +- test/javascripts/lib/click-track-test.js.es6 | 13 +- .../javascripts/lib/link-mentions-test.js.es6 | 4 +- test/javascripts/lib/oneboxer-test.js.es6 | 12 +- test/javascripts/lib/screen-track-test.js.es6 | 4 +- .../lib/upload-short-url-test.js.es6 | 4 +- test/javascripts/lib/user-search-test.js.es6 | 14 +- .../models/post-stream-test.js.es6 | 4 +- test/javascripts/test_helper.js | 34 +- 30 files changed, 1050 insertions(+), 1035 deletions(-) diff --git a/test/javascripts/acceptance/admin-emails-test.js.es6 b/test/javascripts/acceptance/admin-emails-test.js.es6 index f44cf638e9..652dbcf757 100644 --- a/test/javascripts/acceptance/admin-emails-test.js.es6 +++ b/test/javascripts/acceptance/admin-emails-test.js.es6 @@ -1,4 +1,5 @@ import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; acceptance("Admin - Emails", { loggedIn: true }); @@ -16,15 +17,14 @@ Hello, this is a test! This part should be elided.`.trim(); QUnit.test("shows selected and elided text", async assert => { - // prettier-ignore - server.post("/admin/email/advanced-test", () => { // eslint-disable-line no-undef + pretender.post("/admin/email/advanced-test", () => { return [ 200, { "Content-Type": "application/json" }, { format: 1, text: "Hello, this is a test!", - elided: "---\n\nThis part should be elided.", + elided: "---\n\nThis part should be elided." } ]; }); diff --git a/test/javascripts/acceptance/admin-user-emails-test.js.es6 b/test/javascripts/acceptance/admin-user-emails-test.js.es6 index 6fa2965bfb..a9c0c2dcb3 100644 --- a/test/javascripts/acceptance/admin-user-emails-test.js.es6 +++ b/test/javascripts/acceptance/admin-user-emails-test.js.es6 @@ -2,19 +2,6 @@ import { acceptance } from "helpers/qunit-helpers"; acceptance("Admin - User Emails", { loggedIn: true }); -const responseWithSecondary = secondaryEmails => { - return [ - 200, - { "Content-Type": "application/json" }, - { - id: 1, - username: "eviltrout", - email: "eviltrout@example.com", - secondary_emails: secondaryEmails - } - ]; -}; - const assertNoSecondary = assert => { assert.equal( find(".display-row.email .value a").text(), @@ -31,49 +18,40 @@ const assertNoSecondary = assert => { ); }; -const assertMultipleSecondary = assert => { +const assertMultipleSecondary = (assert, firstEmail, secondEmail) => { assert.equal( find(".display-row.secondary-emails .value li:first-of-type a").text(), - "eviltrout1@example.com", + firstEmail, "it should display the first secondary email" ); assert.equal( find(".display-row.secondary-emails .value li:last-of-type a").text(), - "eviltrout2@example.com", + secondEmail, "it should display the second secondary email" ); }; QUnit.test("viewing self without secondary emails", async assert => { - // prettier-ignore - server.get("/admin/users/1.json", () => { // eslint-disable-line no-undef - return responseWithSecondary([]); - }); - await visit("/admin/users/1/eviltrout"); assertNoSecondary(assert); }); QUnit.test("viewing self with multiple secondary emails", async assert => { - // prettier-ignore - server.get("/admin/users/1.json", () => { // eslint-disable-line no-undef - return responseWithSecondary([ - "eviltrout1@example.com", - "eviltrout2@example.com", - ]); - }); - - await visit("/admin/users/1/eviltrout"); + await visit("/admin/users/3/markvanlan"); assert.equal( find(".display-row.email .value a").text(), - "eviltrout@example.com", + "markvanlan@example.com", "it should display the user's primary email" ); - assertMultipleSecondary(assert); + assertMultipleSecondary( + assert, + "markvanlan1@example.com", + "markvanlan2@example.com" + ); }); QUnit.test("viewing another user with no secondary email", async assert => { @@ -84,20 +62,12 @@ QUnit.test("viewing another user with no secondary email", async assert => { }); QUnit.test("viewing another account with secondary emails", async assert => { - // prettier-ignore - server.get("/u/regular/emails.json", () => { // eslint-disable-line no-undef - return [ - 200, - { "Content-Type": "application/json" }, - { - email: "eviltrout@example.com", - secondary_emails: ["eviltrout1@example.com", "eviltrout2@example.com"] - } - ]; - }); - - await visit("/admin/users/1234/regular"); + await visit("/admin/users/1235/regular1"); await click(`.display-row.secondary-emails button`); - assertMultipleSecondary(assert); + assertMultipleSecondary( + assert, + "regular2alt1@example.com", + "regular2alt2@example.com" + ); }); diff --git a/test/javascripts/acceptance/admin-user-index-test.js.es6 b/test/javascripts/acceptance/admin-user-index-test.js.es6 index 6322a0da55..6ea2fd87f0 100644 --- a/test/javascripts/acceptance/admin-user-index-test.js.es6 +++ b/test/javascripts/acceptance/admin-user-index-test.js.es6 @@ -1,10 +1,11 @@ import selectKit from "helpers/select-kit-helper"; import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; acceptance("Admin - User Index", { loggedIn: true, - pretend(server, helper) { - server.get("/groups/search.json", () => { + pretend(pretenderServer, helper) { + pretenderServer.get("/groups/search.json", () => { return helper.response([ { id: 42, @@ -35,8 +36,7 @@ acceptance("Admin - User Index", { }); QUnit.test("can edit username", async assert => { - /* global server */ - server.put("/users/sam/preferences/username", () => [ + pretender.put("/users/sam/preferences/username", () => [ 200, { "Content-Type": "application/json" }, { id: 2, username: "new-sam" } diff --git a/test/javascripts/acceptance/click-track-test.js.es6 b/test/javascripts/acceptance/click-track-test.js.es6 index fe7251fec1..d26e96d5a5 100644 --- a/test/javascripts/acceptance/click-track-test.js.es6 +++ b/test/javascripts/acceptance/click-track-test.js.es6 @@ -1,10 +1,10 @@ +import pretender from "helpers/create-pretender"; import { acceptance } from "helpers/qunit-helpers"; acceptance("Click Track", {}); QUnit.test("Do not track mentions", async assert => { - /* global server */ - server.post("/clicks/track", () => assert.ok(false)); + pretender.post("/clicks/track", () => assert.ok(false)); await visit("/t/internationalization-localization/280"); assert.ok(invisible(".user-card"), "card should not appear"); diff --git a/test/javascripts/acceptance/composer-actions-test.js.es6 b/test/javascripts/acceptance/composer-actions-test.js.es6 index c95497eb08..bd7458ccb0 100644 --- a/test/javascripts/acceptance/composer-actions-test.js.es6 +++ b/test/javascripts/acceptance/composer-actions-test.js.es6 @@ -349,19 +349,21 @@ acceptance("Composer Actions With New Topic Draft", { }, beforeEach() { _clearSnapshots(); - }, - pretend(server, helper) { - server.get("draft.json", () => { - return helper.response({ - draft: - '{"reply":"dum de dum da ba.","action":"createTopic","title":"dum da ba dum dum","categoryId":null,"archetypeId":"regular","metaData":null,"composerTime":540879,"typingTime":3400}', - draft_sequence: 0 - }); - }); } }); +const stubDraftResponse = () => { + sandbox.stub(Draft, "get").returns( + Promise.resolve({ + draft: + '{"reply":"dum de dum da ba.","action":"createTopic","title":"dum da ba dum dum","categoryId":null,"archetypeId":"regular","metaData":null,"composerTime":540879,"typingTime":3400}', + draft_sequence: 0 + }) + ); +}; + QUnit.test("shared draft", async assert => { + stubDraftResponse(); try { toggleCheckDraftPopup(true); @@ -399,6 +401,7 @@ QUnit.test("shared draft", async assert => { } finally { toggleCheckDraftPopup(false); } + sandbox.restore(); }); QUnit.test("reply_as_new_topic with new_topic draft", async assert => { @@ -406,10 +409,12 @@ QUnit.test("reply_as_new_topic with new_topic draft", async assert => { await click(".create.reply"); const composerActions = selectKit(".composer-actions"); await composerActions.expand(); + stubDraftResponse(); await composerActions.selectRowByValue("reply_as_new_topic"); assert.equal( find(".bootbox .modal-body").text(), I18n.t("composer.composer_actions.reply_as_new_topic.confirm") ); await click(".modal-footer .btn.btn-default"); + sandbox.restore(); }); diff --git a/test/javascripts/acceptance/composer-edit-conflict-test.js.es6 b/test/javascripts/acceptance/composer-edit-conflict-test.js.es6 index ee4d22e4c4..890a7dff5c 100644 --- a/test/javascripts/acceptance/composer-edit-conflict-test.js.es6 +++ b/test/javascripts/acceptance/composer-edit-conflict-test.js.es6 @@ -1,18 +1,15 @@ import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; acceptance("Composer - Edit conflict", { loggedIn: true }); QUnit.test("Edit a post that causes an edit conflict", async assert => { - // prettier-ignore - server.put("/posts/398", () => [ // eslint-disable-line no-undef - 409, { "Content-Type": "application/json" }, { errors: ["edit conflict"] } - ]); - await visit("/t/internationalization-localization/280"); await click(".topic-post:eq(0) button.show-more-actions"); await click(".topic-post:eq(0) button.edit"); + await fillIn(".d-editor-input", "this will 409"); await click("#reply-control button.create"); assert.equal( find("#reply-control button.create") @@ -28,14 +25,33 @@ QUnit.test("Edit a post that causes an edit conflict", async assert => { await click(".modal .btn-primary"); }); +function handleDraftPretender(assert) { + pretender.post("/draft.json", request => { + if ( + request.requestBody.indexOf("%22reply%22%3A%22%22") === -1 && + request.requestBody.indexOf("Any+plans+to+support+localization") !== -1 + ) { + assert.notEqual(request.requestBody.indexOf("originalText"), -1); + } + if ( + request.requestBody.indexOf( + "draft_key=topic_280&sequence=4&data=%7B%22reply%22%3A%22hello+world+hello+world+hello+world+hello+world+hello+world%22%2C%22action%22%3A%22reply%22%2C%22categoryId%22%3A2%2C%22archetypeId%22%3A%22regular%22%2C%22metaData" + ) !== -1 + ) { + assert.equal( + request.requestBody.indexOf("originalText"), + -1, + request.requestBody + ); + } + return [200, { "Content-Type": "application/json" }, { success: true }]; + }); +} + QUnit.test( "Should not send originalText when posting a new reply", async assert => { - // prettier-ignore - server.post("/draft.json", request => { // eslint-disable-line no-undef - assert.equal(request.requestBody.indexOf("originalText"), -1, request.requestBody); - return [ 200, { "Content-Type": "application/json" }, { success: true } ]; - }); + handleDraftPretender(assert); await visit("/t/internationalization-localization/280"); await click(".topic-post:eq(0) button.reply"); @@ -47,13 +63,7 @@ QUnit.test( ); QUnit.test("Should send originalText when editing a reply", async assert => { - // prettier-ignore - server.post("/draft.json", request => { // eslint-disable-line no-undef - if (request.requestBody.indexOf("%22reply%22%3A%22%22") === -1) { - assert.notEqual(request.requestBody.indexOf("originalText"), -1); - } - return [ 200, { "Content-Type": "application/json" }, { success: true } ]; - }); + handleDraftPretender(assert); await visit("/t/internationalization-localization/280"); await click(".topic-post:eq(0) button.show-more-actions"); diff --git a/test/javascripts/acceptance/composer-test.js.es6 b/test/javascripts/acceptance/composer-test.js.es6 index 47f2fc99a3..b9da96ee5e 100644 --- a/test/javascripts/acceptance/composer-test.js.es6 +++ b/test/javascripts/acceptance/composer-test.js.es6 @@ -2,17 +2,13 @@ import { run } from "@ember/runloop"; import selectKit from "helpers/select-kit-helper"; import { acceptance } from "helpers/qunit-helpers"; import { toggleCheckDraftPopup } from "discourse/controllers/composer"; +import Draft from "discourse/models/draft"; +import { Promise } from "rsvp"; acceptance("Composer", { loggedIn: true, - pretend(server, helper) { - server.get("/draft.json", () => { - return helper.response({ - draft: null, - draft_sequence: 42 - }); - }); - server.post("/uploads/lookup-urls", () => { + pretend(pretenderServer, helper) { + pretenderServer.post("/uploads/lookup-urls", () => { return helper.response([]); }); }, @@ -617,14 +613,6 @@ QUnit.test("Checks for existing draft", async assert => { try { toggleCheckDraftPopup(true); - // prettier-ignore - server.get("/draft.json", () => { // eslint-disable-line no-undef - return [ 200, { "Content-Type": "application/json" }, { - draft: "{\"reply\":\"This is a draft of the first post\",\"action\":\"reply\",\"categoryId\":1,\"archetypeId\":\"regular\",\"metaData\":null,\"composerTime\":2863,\"typingTime\":200}", - draft_sequence: 42 - } ]; - }); - await visit("/t/internationalization-localization/280"); await click(".topic-post:eq(0) button.show-more-actions"); @@ -646,18 +634,17 @@ QUnit.test("Can switch states without abandon popup", async assert => { const longText = "a".repeat(256); + sandbox.stub(Draft, "get").returns( + Promise.resolve({ + draft: null, + draft_sequence: 0 + }) + ); + await click(".btn-primary.create.btn"); await fillIn(".d-editor-input", longText); - // prettier-ignore - server.get("/draft.json", () => { // eslint-disable-line no-undef - return [ 200, { "Content-Type": "application/json" }, { - draft: "{\"reply\":\"This is a draft of the first post\",\"action\":\"reply\",\"categoryId\":1,\"archetypeId\":\"regular\",\"metaData\":null,\"composerTime\":2863,\"typingTime\":200}", - draft_sequence: 42 - } ]; - }); - await click("article#post_3 button.reply"); const composerActions = selectKit(".composer-actions"); @@ -686,19 +673,20 @@ QUnit.test("Can switch states without abandon popup", async assert => { } finally { toggleCheckDraftPopup(false); } + sandbox.restore(); }); QUnit.test("Loading draft also replaces the recipients", async assert => { try { toggleCheckDraftPopup(true); - // prettier-ignore - server.get("/draft.json", () => { // eslint-disable-line no-undef - return [ 200, { "Content-Type": "application/json" }, { - "draft":"{\"reply\":\"hello\",\"action\":\"privateMessage\",\"title\":\"hello\",\"categoryId\":null,\"archetypeId\":\"private_message\",\"metaData\":null,\"usernames\":\"codinghorror\",\"composerTime\":9159,\"typingTime\":2500}", - "draft_sequence":0 - } ]; - }); + sandbox.stub(Draft, "get").returns( + Promise.resolve({ + draft: + '{"reply":"hello","action":"privateMessage","title":"hello","categoryId":null,"archetypeId":"private_message","metaData":null,"usernames":"codinghorror","composerTime":9159,"typingTime":2500}', + draft_sequence: 0 + }) + ); await visit("/u/charlie"); await click("button.compose-pm"); diff --git a/test/javascripts/acceptance/composer-uncategorized-test.js.es6 b/test/javascripts/acceptance/composer-uncategorized-test.js.es6 index 7ca84df311..46dac33167 100644 --- a/test/javascripts/acceptance/composer-uncategorized-test.js.es6 +++ b/test/javascripts/acceptance/composer-uncategorized-test.js.es6 @@ -3,14 +3,6 @@ import { acceptance, updateCurrentUser } from "helpers/qunit-helpers"; acceptance("Composer and uncategorized is not allowed", { loggedIn: true, - pretend(server, helper) { - server.get("/draft.json", () => { - return helper.response({ - draft: null, - draft_sequence: 42 - }); - }); - }, settings: { enable_whispers: true, allow_uncategorized_topics: false diff --git a/test/javascripts/acceptance/group-test.js.es6 b/test/javascripts/acceptance/group-test.js.es6 index af5bc39935..9ba5a9f2f0 100644 --- a/test/javascripts/acceptance/group-test.js.es6 +++ b/test/javascripts/acceptance/group-test.js.es6 @@ -1,12 +1,13 @@ import selectKit from "helpers/select-kit-helper"; import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; let groupArgs = { settings: { enable_group_directory: true }, - pretend(server, helper) { - server.post("/groups/Macdonald/request_membership", () => { + pretend(pretenderServer, helper) { + pretenderServer.post("/groups/Macdonald/request_membership", () => { return helper.response({ relative_url: "/t/internationalization-localization/280" }); @@ -127,10 +128,12 @@ QUnit.test("User Viewing Group", async assert => { QUnit.test( "Admin viewing group messages when there are no messages", async assert => { - // prettier-ignore - server.get("/topics/private-messages-group/eviltrout/discourse.json", () => { // eslint-disable-line no-undef - return response({ topic_list: { topics: [] } }); - }); + pretender.get( + "/topics/private-messages-group/eviltrout/discourse.json", + () => { + return response({ topic_list: { topics: [] } }); + } + ); await visit("/g/discourse"); await click(".nav-pills li a[title='Messages']"); @@ -146,87 +149,89 @@ QUnit.test( ); QUnit.test("Admin viewing group messages", async assert => { - // prettier-ignore - server.get("/topics/private-messages-group/eviltrout/discourse.json", () => { // eslint-disable-line no-undef - return response({ - users: [ - { - id: 2, - username: "bruce1", - avatar_template: - "/user_avatar/meta.discourse.org/bruce1/{size}/5245.png" - }, - { - id: 3, - username: "CodingHorror", - avatar_template: - "/user_avatar/meta.discourse.org/codinghorror/{size}/5245.png" - } - ], - primary_groups: [], - topic_list: { - can_create_topic: true, - draft: null, - draft_key: "new_topic", - draft_sequence: 0, - per_page: 30, - topics: [ + pretender.get( + "/topics/private-messages-group/eviltrout/discourse.json", + () => { + return response({ + users: [ { - id: 12199, - title: "This is a private message 1", - fancy_title: "This is a private message 1", - slug: "this-is-a-private-message-1", - posts_count: 0, - reply_count: 0, - highest_post_number: 0, - image_url: null, - created_at: "2018-03-16T03:38:45.583Z", - last_posted_at: null, - bumped: true, - bumped_at: "2018-03-16T03:38:45.583Z", - unseen: false, - pinned: false, - unpinned: null, - visible: true, - closed: false, - archived: false, - bookmarked: null, - liked: null, - views: 0, - like_count: 0, - has_summary: false, - archetype: "private_message", - last_poster_username: "bruce1", - category_id: null, - pinned_globally: false, - featured_link: null, - posters: [ - { - extras: "latest single", - description: "Original Poster, Most Recent Poster", - user_id: 2, - primary_group_id: null - } - ], - participants: [ - { - extras: "latest", - description: null, - user_id: 2, - primary_group_id: null - }, - { - extras: null, - description: null, - user_id: 3, - primary_group_id: null - } - ] + id: 2, + username: "bruce1", + avatar_template: + "/user_avatar/meta.discourse.org/bruce1/{size}/5245.png" + }, + { + id: 3, + username: "CodingHorror", + avatar_template: + "/user_avatar/meta.discourse.org/codinghorror/{size}/5245.png" } - ] - } - }); - }); + ], + primary_groups: [], + topic_list: { + can_create_topic: true, + draft: null, + draft_key: "new_topic", + draft_sequence: 0, + per_page: 30, + topics: [ + { + id: 12199, + title: "This is a private message 1", + fancy_title: "This is a private message 1", + slug: "this-is-a-private-message-1", + posts_count: 0, + reply_count: 0, + highest_post_number: 0, + image_url: null, + created_at: "2018-03-16T03:38:45.583Z", + last_posted_at: null, + bumped: true, + bumped_at: "2018-03-16T03:38:45.583Z", + unseen: false, + pinned: false, + unpinned: null, + visible: true, + closed: false, + archived: false, + bookmarked: null, + liked: null, + views: 0, + like_count: 0, + has_summary: false, + archetype: "private_message", + last_poster_username: "bruce1", + category_id: null, + pinned_globally: false, + featured_link: null, + posters: [ + { + extras: "latest single", + description: "Original Poster, Most Recent Poster", + user_id: 2, + primary_group_id: null + } + ], + participants: [ + { + extras: "latest", + description: null, + user_id: 2, + primary_group_id: null + }, + { + extras: null, + description: null, + user_id: 3, + primary_group_id: null + } + ] + } + ] + } + }); + } + ); await visit("/g/discourse"); await click(".nav-pills li a[title='Messages']"); diff --git a/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6 b/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6 index 89f8fd5a4c..b238e36118 100644 --- a/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6 +++ b/test/javascripts/acceptance/keyboard-shortcuts-test.js.es6 @@ -1,16 +1,16 @@ import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; acceptance("Keyboard Shortcuts", { loggedIn: true }); test("go to first suggested topic", async assert => { - /* global server */ - server.get("/t/27331/4.json", () => [ + pretender.get("/t/27331/4.json", () => [ 200, { "Content-Type": "application/json" }, {} ]); - server.get("/t/27331.json", () => [ + pretender.get("/t/27331.json", () => [ 200, { "Content-Type": "application/json" }, {} @@ -20,7 +20,7 @@ test("go to first suggested topic", async assert => { * No suggested topics exist. */ - server.get("/t/9/last.json", () => [ + pretender.get("/t/9/last.json", () => [ 200, { "Content-Type": "application/json" }, {} @@ -44,7 +44,7 @@ test("go to first suggested topic", async assert => { * Suggested topic is returned by server. */ - server.get("/t/28830/last.json", () => [ + pretender.get("/t/28830/last.json", () => [ 200, { "Content-Type": "application/json" }, { diff --git a/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6 b/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6 index a205a12d05..1c12c1f055 100644 --- a/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6 +++ b/test/javascripts/acceptance/login-with-email-and-hide-email-address-taken-test.js.es6 @@ -1,4 +1,5 @@ import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; acceptance("Login with email - hide email address taken", { settings: { @@ -10,8 +11,7 @@ acceptance("Login with email - hide email address taken", { return [200, { "Content-Type": "application/json" }, object]; }; - // prettier-ignore - server.post("/u/email-login", () => { // eslint-disable-line no-undef + pretender.post("/u/email-login", () => { return response({ success: "OK" }); }); } diff --git a/test/javascripts/acceptance/tags-test.js.es6 b/test/javascripts/acceptance/tags-test.js.es6 index 276c814a91..e3a6449aa4 100644 --- a/test/javascripts/acceptance/tags-test.js.es6 +++ b/test/javascripts/acceptance/tags-test.js.es6 @@ -1,4 +1,6 @@ import { updateCurrentUser, acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; + acceptance("Tags", { loggedIn: true }); QUnit.test("list the tags", async assert => { @@ -19,48 +21,6 @@ acceptance("Tags listed by group", { }); QUnit.test("list the tags in groups", async assert => { - // prettier-ignore - server.get("/tags", () => { // eslint-disable-line no-undef - return [ - 200, - { "Content-Type": "application/json" }, - { - tags: [ - { id: "planned", text: "planned", count: 7, pm_count: 0 }, - { id: "private", text: "private", count: 0, pm_count: 7 } - ], - extras: { - tag_groups: [ - { - id: 2, - name: "Ford Cars", - tags: [ - { id: "Escort", text: "Escort", count: 1, pm_count: 0 }, - { id: "focus", text: "focus", count: 3, pm_count: 0 } - ] - }, - { - id: 1, - name: "Honda Cars", - tags: [ - { id: "civic", text: "civic", count: 4, pm_count: 0 }, - { id: "accord", text: "accord", count: 2, pm_count: 0 } - ] - }, - { - id: 1, - name: "Makes", - tags: [ - { id: "ford", text: "ford", count: 5, pm_count: 0 }, - { id: "honda", text: "honda", count: 6, pm_count: 0 } - ] - } - ] - } - } - ]; - }); - await visit("/tags"); assert.equal( $(".tag-list").length, @@ -102,14 +62,13 @@ QUnit.test("list the tags in groups", async assert => { }); test("new topic button is not available for staff-only tags", async assert => { - /* global server */ - server.get("/tag/regular-tag/notifications", () => [ + pretender.get("/tag/regular-tag/notifications", () => [ 200, { "Content-Type": "application/json" }, { tag_notification: { id: "regular-tag", notification_level: 1 } } ]); - server.get("/tag/regular-tag/l/latest.json", () => [ + pretender.get("/tag/regular-tag/l/latest.json", () => [ 200, { "Content-Type": "application/json" }, { @@ -133,13 +92,13 @@ test("new topic button is not available for staff-only tags", async assert => { } ]); - server.get("/tag/staff-only-tag/notifications", () => [ + pretender.get("/tag/staff-only-tag/notifications", () => [ 200, { "Content-Type": "application/json" }, { tag_notification: { id: "staff-only-tag", notification_level: 1 } } ]); - server.get("/tag/staff-only-tag/l/latest.json", () => [ + pretender.get("/tag/staff-only-tag/l/latest.json", () => [ 200, { "Content-Type": "application/json" }, { @@ -286,7 +245,7 @@ test("tag info can show synonyms", async assert => { }); test("admin can manage tags", async assert => { - server.delete("/tag/planters/synonyms/containers", () => [ + pretender.delete("/tag/planters/synonyms/containers", () => [ 200, { "Content-Type": "application/json" }, { success: true } diff --git a/test/javascripts/acceptance/user-test.js.es6 b/test/javascripts/acceptance/user-test.js.es6 index 2f2fc61d08..24f630b942 100644 --- a/test/javascripts/acceptance/user-test.js.es6 +++ b/test/javascripts/acceptance/user-test.js.es6 @@ -1,10 +1,12 @@ import { acceptance } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; +import Draft from "discourse/models/draft"; +import { Promise } from "rsvp"; acceptance("User", { loggedIn: true }); QUnit.test("Invalid usernames", async assert => { - // prettier-ignore - server.get("/u/eviltrout%2F..%2F..%2F.json", () => { // eslint-disable-line no-undef + pretender.get("/u/eviltrout%2F..%2F..%2F.json", () => { return [400, { "Content-Type": "application/json" }, {}]; }); @@ -67,13 +69,12 @@ QUnit.test("Viewing Summary", async assert => { }); QUnit.test("Viewing Drafts", async assert => { - // prettier-ignore - server.get("/draft.json", () => { // eslint-disable-line no-undef - return [ 200, { "Content-Type": "application/json" }, { - draft: "{\"reply\":\"This is a draft of the first post\",\"action\":\"reply\",\"categoryId\":1,\"archetypeId\":\"regular\",\"metaData\":null,\"composerTime\":2863,\"typingTime\":200}", - draft_sequence: 42 - } ]; - }); + sandbox.stub(Draft, "get").returns( + Promise.resolve({ + draft: null, + draft_sequence: 0 + }) + ); await visit("/u/eviltrout/activity/drafts"); assert.ok(exists(".user-stream"), "has drafts stream"); @@ -87,4 +88,5 @@ QUnit.test("Viewing Drafts", async assert => { exists(".d-editor-input"), "composer is visible after resuming a draft" ); + sandbox.restore(); }); diff --git a/test/javascripts/components/admin-report-test.js.es6 b/test/javascripts/components/admin-report-test.js.es6 index e713ff693d..dfbab4c64f 100644 --- a/test/javascripts/components/admin-report-test.js.es6 +++ b/test/javascripts/components/admin-report-test.js.es6 @@ -1,4 +1,5 @@ import componentTest from "helpers/component-test"; +import pretender from "helpers/create-pretender"; moduleForComponent("admin-report", { integration: true @@ -133,13 +134,18 @@ componentTest("exception", { componentTest("rate limited", { beforeEach() { - const response = object => { - return [429, { "Content-Type": "application/json" }, object]; - }; - - // prettier-ignore - server.get("/admin/reports/bulk", () => { //eslint-disable-line - return response({"errors":["You’ve performed this action too many times. Please wait 10 seconds before trying again."],"error_type":"rate_limit","extras":{"wait_seconds":10}}); + pretender.get("/admin/reports/bulk", () => { + return [ + 429, + { "Content-Type": "application/json" }, + { + errors: [ + "You’ve performed this action too many times. Please wait 10 seconds before trying again." + ], + error_type: "rate_limit", + extras: { wait_seconds: 10 } + } + ]; }); }, diff --git a/test/javascripts/components/badge-title-test.js.es6 b/test/javascripts/components/badge-title-test.js.es6 index 8f1630f844..7be2678269 100644 --- a/test/javascripts/components/badge-title-test.js.es6 +++ b/test/javascripts/components/badge-title-test.js.es6 @@ -1,6 +1,7 @@ import selectKit from "helpers/select-kit-helper"; import componentTest from "helpers/component-test"; import EmberObject from "@ember/object"; +import pretender from "helpers/create-pretender"; moduleForComponent("badge-title", { integration: true }); @@ -23,8 +24,7 @@ componentTest("badge title", { }, async test(assert) { - /* global server */ - server.put("/u/eviltrout/preferences/badge_title", () => [ + pretender.put("/u/eviltrout/preferences/badge_title", () => [ 200, { "Content-Type": "application/json" }, {} diff --git a/test/javascripts/components/select-kit/tag-drop-test.js.es6 b/test/javascripts/components/select-kit/tag-drop-test.js.es6 index 5d758fa90b..2c6d156052 100644 --- a/test/javascripts/components/select-kit/tag-drop-test.js.es6 +++ b/test/javascripts/components/select-kit/tag-drop-test.js.es6 @@ -2,6 +2,7 @@ import componentTest from "helpers/component-test"; import { testSelectKitModule } from "./select-kit-test-helper"; import Site from "discourse/models/site"; import { set } from "@ember/object"; +import pretender from "helpers/create-pretender"; testSelectKitModule("tag-drop", { beforeEach() { @@ -12,19 +13,14 @@ testSelectKitModule("tag-drop", { return [200, { "Content-Type": "application/json" }, object]; }; - // prettier-ignore - server.get("/tags/filter/search", (params) => { //eslint-disable-line + pretender.get("/tags/filter/search", params => { if (params.queryParams.q === "rég") { return response({ - "results": [ - { "id": "régis", "text": "régis", "count": 2, "pm_count": 0 } - ] + results: [{ id: "régis", text: "régis", count: 2, pm_count: 0 }] }); - }else if (params.queryParams.q === "dav") { + } else if (params.queryParams.q === "dav") { return response({ - "results": [ - { "id": "David", "text": "David", "count": 2, "pm_count": 0 } - ] + results: [{ id: "David", text: "David", count: 2, pm_count: 0 }] }); } }); diff --git a/test/javascripts/components/select-kit/user-chooser-test.js.es6 b/test/javascripts/components/select-kit/user-chooser-test.js.es6 index 068d8c6a1f..c59d7cb571 100644 --- a/test/javascripts/components/select-kit/user-chooser-test.js.es6 +++ b/test/javascripts/components/select-kit/user-chooser-test.js.es6 @@ -1,5 +1,6 @@ import componentTest from "helpers/component-test"; import { testSelectKitModule } from "./select-kit-test-helper"; +import pretender from "helpers/create-pretender"; testSelectKitModule("user-chooser"); @@ -42,9 +43,8 @@ componentTest("can add a username", { return [200, { "Content-Type": "application/json" }, object]; }; - // prettier-ignore - server.get("/u/search/users", () => { //eslint-disable-line - return response({users:[{username: "maja", name: "Maja"}]}); + pretender.get("/u/search/users", () => { + return response({ users: [{ username: "maja", name: "Maja" }] }); }); }, diff --git a/test/javascripts/controllers/topic-test.js.es6 b/test/javascripts/controllers/topic-test.js.es6 index da92e3df31..4277564fad 100644 --- a/test/javascripts/controllers/topic-test.js.es6 +++ b/test/javascripts/controllers/topic-test.js.es6 @@ -5,6 +5,7 @@ import PostStream from "discourse/models/post-stream"; import { Placeholder } from "discourse/lib/posts-with-placeholders"; import User from "discourse/models/user"; import { Promise } from "rsvp"; +import pretender from "helpers/create-pretender"; moduleFor("controller:topic", "controller:topic", { needs: [ @@ -522,8 +523,7 @@ QUnit.test("topVisibleChanged", function(assert) { QUnit.test( "deletePost - no modal is shown if post does not have replies", function(assert) { - /* global server */ - server.get("/posts/2/reply-ids.json", () => { + pretender.get("/posts/2/reply-ids.json", () => { return [200, { "Content-Type": "application/json" }, []]; }); diff --git a/test/javascripts/fixtures/draft.js.es6 b/test/javascripts/fixtures/draft.js.es6 index bdbdfed17c..a1d5ce6b9c 100644 --- a/test/javascripts/fixtures/draft.js.es6 +++ b/test/javascripts/fixtures/draft.js.es6 @@ -2,5 +2,20 @@ export default { "/draft.json": { draft: null, draft_sequence: 0 + }, + "/draft.json?draft_key=topic_280": { + draft: + '{"reply":"This is a draft of the first post","action":"reply","categoryId":1,"archetypeId":"regular","metaData":null,"composerTime":2863,"typingTime":200}', + draft_sequence: 42 + }, + "/draft.json?draft_key=topic_281": { + draft: + '{"reply":"dum de dum da ba.","action":"createTopic","title":"dum da ba dum dum","categoryId":null,"archetypeId":"regular","metaData":null,"composerTime":540879,"typingTime":3400}', + draft_sequence: 0 + }, + "/draft.json?draft_key=topic_9": { + draft: + '{"reply":"This is a draft of the first post","action":"reply","categoryId":1,"archetypeId":"regular","metaData":null,"composerTime":2863,"typingTime":200}', + draft_sequence: 42 } }; diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index 5efd61e9a8..76cca6fa51 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -33,724 +33,794 @@ export function success() { const loggedIn = () => !!User.current(); const helpers = { response, success, parsePostData }; + export let fixturesByUrl; -export default function() { - const server = new Pretender(function() { - // Autoload any `*-pretender` files - Object.keys(requirejs.entries).forEach(e => { - let m = e.match(/^.*helpers\/([a-z-]+)\-pretender$/); - if (m && m[1] !== "create") { - let result = requirejs(e).default.call(this, helpers); - if (m[1] === "fixture") { - fixturesByUrl = result; - } +export default new Pretender(); + +export function applyDefaultHandlers(pretender) { + // Autoload any `*-pretender` files + Object.keys(requirejs.entries).forEach(e => { + let m = e.match(/^.*helpers\/([a-z-]+)\-pretender$/); + if (m && m[1] !== "create") { + let result = requirejs(e).default.call(pretender, helpers); + if (m[1] === "fixture") { + fixturesByUrl = result; } - }); + } + }); - this.get("/admin/plugins", () => response({ plugins: [] })); + pretender.get("/admin/plugins", () => response({ plugins: [] })); - this.get("/composer_messages", () => response({ composer_messages: [] })); + pretender.get("/composer_messages", () => + response({ composer_messages: [] }) + ); - this.get("/latest.json", () => { - const json = fixturesByUrl["/latest.json"]; + pretender.get("/latest.json", () => { + const json = fixturesByUrl["/latest.json"]; - if (loggedIn()) { - // Stuff to let us post - json.topic_list.can_create_topic = true; - json.topic_list.draft_key = "new_topic"; - json.topic_list.draft_sequence = 1; - } - return response(json); - }); + if (loggedIn()) { + // Stuff to let us post + json.topic_list.can_create_topic = true; + json.topic_list.draft_key = "new_topic"; + json.topic_list.draft_sequence = 1; + } + return response(json); + }); - this.get("/c/bug/1/l/latest.json", () => { - const json = fixturesByUrl["/c/bug/1/l/latest.json"]; + pretender.get("/c/bug/1/l/latest.json", () => { + const json = fixturesByUrl["/c/bug/1/l/latest.json"]; - if (loggedIn()) { - // Stuff to let us post - json.topic_list.can_create_topic = true; - json.topic_list.draft_key = "new_topic"; - json.topic_list.draft_sequence = 1; - } - return response(json); - }); + if (loggedIn()) { + // Stuff to let us post + json.topic_list.can_create_topic = true; + json.topic_list.draft_key = "new_topic"; + json.topic_list.draft_sequence = 1; + } + return response(json); + }); - this.get("/tags", () => { - return response({ + pretender.get("/tags", () => { + return [ + 200, + { "Content-Type": "application/json" }, + { tags: [ - { - id: "eviltrout", - count: 1 - } - ] - }); - }); - - this.get("/tags/filter/search", () => { - return response({ results: [{ text: "monkey", count: 1 }] }); - }); - - this.get(`/u/:username/emails.json`, () => { - return response({ email: "eviltrout@example.com" }); - }); - - this.get("/u/eviltrout.json", () => { - const json = fixturesByUrl["/u/eviltrout.json"]; - json.user.can_edit = loggedIn(); - return response(json); - }); - - this.get("/u/eviltrout/summary.json", () => { - return response({ - user_summary: { - topic_ids: [1234], - replies: [{ topic_id: 1234 }], - links: [{ topic_id: 1234, url: "https://eviltrout.com" }], - most_replied_to_users: [{ id: 333 }], - most_liked_by_users: [{ id: 333 }], - most_liked_users: [{ id: 333 }], - badges: [{ badge_id: 444 }], - top_categories: [ + { id: "eviltrout", count: 1 }, + { id: "planned", text: "planned", count: 7, pm_count: 0 }, + { id: "private", text: "private", count: 0, pm_count: 7 } + ], + extras: { + tag_groups: [ + { + id: 2, + name: "Ford Cars", + tags: [ + { id: "Escort", text: "Escort", count: 1, pm_count: 0 }, + { id: "focus", text: "focus", count: 3, pm_count: 0 } + ] + }, { id: 1, - name: "bug", - color: "e9dd00", - text_color: "000000", - slug: "bug", - read_restricted: false, - parent_category_id: null, - topic_count: 1, - post_count: 1 + name: "Honda Cars", + tags: [ + { id: "civic", text: "civic", count: 4, pm_count: 0 }, + { id: "accord", text: "accord", count: 2, pm_count: 0 } + ] + }, + { + id: 1, + name: "Makes", + tags: [ + { id: "ford", text: "ford", count: 5, pm_count: 0 }, + { id: "honda", text: "honda", count: 6, pm_count: 0 } + ] } ] - }, - badges: [{ id: 444, count: 1 }], - topics: [{ id: 1234, title: "cool title", url: "/t/1234/cool-title" }] - }); - }); - - this.get("/u/eviltrout/invited_count.json", () => { - return response({ - counts: { pending: 1, redeemed: 0, total: 0 } - }); - }); - - this.get("/u/eviltrout/invited.json", () => { - return response({ invites: [{ id: 1 }] }); - }); - - this.get("/topics/private-messages/eviltrout.json", () => { - return response(fixturesByUrl["/topics/private-messages/eviltrout.json"]); - }); - - this.get("/topics/feature_stats.json", () => { - return response({ - pinned_in_category_count: 0, - pinned_globally_count: 0, - banner_count: 0 - }); - }); - - this.put("/t/34/convert-topic/public", () => { - return response({}); - }); - - this.put("/t/280/make-banner", () => { - return response({}); - }); - - this.put("/t/internationalization-localization/280/status", () => { - return response({ - success: "OK", - topic_status_update: null - }); - }); - - this.post("/clicks/track", success); - - this.get("/search", request => { - if (request.queryParams.q === "posts") { - return response({ - posts: [ - { - id: 1234 - } - ] - }); - } else if (request.queryParams.q === "evil") { - return response({ - posts: [ - { - id: 1234 - } - ], - tags: [ - { - id: 6, - name: "eviltrout" - } - ] - }); + } } + ]; + }); - return response({}); - }); + pretender.get("/tags/filter/search", () => { + return response({ results: [{ text: "monkey", count: 1 }] }); + }); - this.put("/u/eviltrout.json", () => response({ user: {} })); - - this.get("/t/280.json", () => response(fixturesByUrl["/t/280/1.json"])); - this.get("/t/34.json", () => response(fixturesByUrl["/t/34/1.json"])); - this.get("/t/280/:post_number.json", () => - response(fixturesByUrl["/t/280/1.json"]) - ); - this.get("/t/28830.json", () => response(fixturesByUrl["/t/28830/1.json"])); - this.get("/t/9.json", () => response(fixturesByUrl["/t/9/1.json"])); - this.get("/t/12.json", () => response(fixturesByUrl["/t/12/1.json"])); - this.put("/t/1234/re-pin", success); - - this.get("/t/id_for/:slug", () => { + pretender.get(`/u/:username/emails.json`, request => { + if (request.params.username === "regular2") { return response({ - id: 280, - slug: "internationalization-localization", - url: "/t/internationalization-localization/280" + email: "regular2@example.com", + secondary_emails: [ + "regular2alt1@example.com", + "regular2alt2@example.com" + ] }); - }); + } + return response({ email: "eviltrout@example.com" }); + }); - this.delete("/t/:id", success); - this.put("/t/:id/recover", success); - this.put("/t/:id/publish", success); + pretender.get("/u/eviltrout.json", () => { + const json = fixturesByUrl["/u/eviltrout.json"]; + json.user.can_edit = loggedIn(); + return response(json); + }); - this.get("/404-body", () => { - return [ - 200, - { "Content-Type": "text/html" }, - "
not found
" - ]; - }); - - this.delete("/draft.json", success); - this.post("/draft.json", success); - - this.get("/u/:username/staff-info.json", () => response({})); - - this.get("/post_action_users", () => { - return response({ - post_action_users: [ + pretender.get("/u/eviltrout/summary.json", () => { + return response({ + user_summary: { + topic_ids: [1234], + replies: [{ topic_id: 1234 }], + links: [{ topic_id: 1234, url: "https://eviltrout.com" }], + most_replied_to_users: [{ id: 333 }], + most_liked_by_users: [{ id: 333 }], + most_liked_users: [{ id: 333 }], + badges: [{ badge_id: 444 }], + top_categories: [ { id: 1, - username: "eviltrout", - avatar_template: "/user_avatar/default/eviltrout/{size}/1.png", - username_lower: "eviltrout" + name: "bug", + color: "e9dd00", + text_color: "000000", + slug: "bug", + read_restricted: false, + parent_category_id: null, + topic_count: 1, + post_count: 1 } ] - }); - }); - - this.get("/post_replies", () => { - return response({ post_replies: [{ id: 1234, cooked: "wat" }] }); - }); - - this.get("/post_reply_histories", () => { - return response({ post_reply_histories: [{ id: 1234, cooked: "wat" }] }); - }); - - this.get("/category_hashtags/check", () => { - return response({ valid: [{ slug: "bug", url: "/c/bugs" }] }); - }); - - this.get("/categories_and_latest", () => - response(fixturesByUrl["/categories_and_latest.json"]) - ); - - this.put("/categories/:category_id", request => { - const category = parsePostData(request.requestBody); - category.id = parseInt(request.params.category_id, 10); - - if (category.email_in === "duplicate@example.com") { - return response(422, { errors: ["duplicate email"] }); - } - - return response({ category }); - }); - - this.get("/draft.json", request => { - if (request.queryParams.draft_key === "new_topic") { - return response(fixturesByUrl["/draft.json"]); - } - - return response({}); - }); - - this.get("/drafts.json", () => response(fixturesByUrl["/drafts.json"])); - - this.put("/queued_posts/:queued_post_id", function(request) { - return response({ queued_post: { id: request.params.queued_post_id } }); - }); - - this.get("/queued_posts", function() { - return response({ - queued_posts: [ - { id: 1, raw: "queued post text", can_delete_user: true } - ] - }); - }); - - this.post("/session", function(request) { - const data = parsePostData(request.requestBody); - - if (data.password === "correct") { - return response({ username: "eviltrout" }); - } - - if (data.password === "not-activated") { - return response({ - error: "not active", - reason: "not_activated", - sent_to_email: "eviltrout@example.com", - current_email: "current@example.com" - }); - } - - if (data.password === "not-activated-edit") { - return response({ - error: "not active", - reason: "not_activated", - sent_to_email: "eviltrout@example.com", - current_email: "current@example.com" - }); - } - - if (data.password === "need-second-factor") { - if (data.second_factor_token && data.second_factor_token === "123456") { - return response({ username: "eviltrout" }); - } - - return response({ - failed: "FAILED", - ok: false, - error: - "Invalid authentication code. Each code can only be used once.", - reason: "invalid_second_factor", - backup_enabled: true, - security_key_enabled: false, - totp_enabled: true, - multiple_second_factor_methods: false - }); - } - - if (data.password === "need-security-key") { - if (data.securityKeyCredential) { - return response({ username: "eviltrout" }); - } - - return response({ - failed: "FAILED", - ok: false, - error: - "The selected second factor method is not enabled for your account.", - reason: "not_enabled_second_factor_method", - backup_enabled: false, - security_key_enabled: true, - totp_enabled: false, - multiple_second_factor_methods: false, - allowed_credential_ids: ["allowed_credential_ids"], - challenge: "challenge" - }); - } - - return response(400, { error: "invalid login" }); - }); - - this.post("/u/action/send_activation_email", success); - this.put("/u/update-activation-email", success); - - this.get("/u/hp.json", function() { - return response({ - value: "32faff1b1ef1ac3", - challenge: "61a3de0ccf086fb9604b76e884d75801" - }); - }); - - this.get("/session/csrf", function() { - return response({ csrf: "mgk906YLagHo2gOgM1ddYjAN4hQolBdJCqlY6jYzAYs=" }); - }); - - this.get("/groups/check-name", () => { - return response({ available: true }); - }); - - this.get("/u/check_username", function(request) { - if (request.queryParams.username === "taken") { - return response({ available: false, suggestion: "nottaken" }); - } - return response({ available: true }); - }); - - this.post("/u", () => response({ success: true })); - - this.get("/login.html", () => [200, {}, "LOGIN PAGE"]); - - this.delete("/posts/:post_id", success); - this.put("/posts/:post_id/recover", success); - this.get("/posts/:post_id/expand-embed", success); - - this.put("/posts/:post_id", request => { - const data = parsePostData(request.requestBody); - data.post.id = request.params.post_id; - data.post.version = 2; - return response(200, data.post); - }); - - this.get("/t/403.json", () => response(403, {})); - this.get("/t/404.json", () => response(404, "not found")); - this.get("/t/500.json", () => response(502, {})); - - this.put("/t/:slug/:id", request => { - const isJSON = request.requestHeaders["Content-Type"].includes( - "application/json" - ); - - const data = isJSON - ? JSON.parse(request.requestBody) - : parsePostData(request.requestBody); - - return response(200, { - basic_topic: { - id: request.params.id, - title: data.title, - fancy_title: data.title, - slug: request.params.slug - } - }); - }); - - this.get("groups", () => { - return response(200, fixturesByUrl["/groups.json"]); - }); - - this.get("/groups.json", () => { - return response(200, fixturesByUrl["/groups.json?username=eviltrout"]); - }); - - this.get("groups/search.json", () => { - return response(200, []); - }); - - this.get("/topics/groups/discourse.json", () => { - return response(200, fixturesByUrl["/topics/groups/discourse.json"]); - }); - - this.get("/groups/discourse/mentions.json", () => { - return response(200, fixturesByUrl["/groups/discourse/posts.json"]); - }); - - this.get("/groups/discourse/messages.json", () => { - return response(200, fixturesByUrl["/groups/discourse/posts.json"]); - }); - - this.get("/groups/moderators/members.json", () => { - return response(200, fixturesByUrl["/groups/discourse/members.json"]); - }); - - this.get("/t/:topic_id/posts.json", request => { - const postIds = request.queryParams.post_ids; - const postNumber = parseInt(request.queryParams.post_number, 10); - let posts; - - if (postIds) { - posts = postIds.map(p => ({ - id: parseInt(p, 10), - post_number: parseInt(p, 10) - })); - } else if (postNumber && request.queryParams.asc === "true") { - posts = _.range(postNumber + 1, postNumber + 6).map(p => ({ - id: parseInt(p, 10), - post_number: parseInt(p, 10) - })); - } else if (postNumber && request.queryParams.asc === "false") { - posts = _.range(postNumber - 5, postNumber) - .reverse() - .map(p => ({ - id: parseInt(p, 10), - post_number: parseInt(p, 10) - })); - } - - return response(200, { post_stream: { posts } }); - }); - - this.get("/posts/:post_id/reply-history.json", () => { - return response(200, [{ id: 2222, post_number: 2222 }]); - }); - - this.get("/posts/:post_id/reply-ids.json", () => { - return response(200, { - direct_reply_ids: [45], - all_reply_ids: [45, 100] - }); - }); - - this.post("/user_badges", () => - response(200, fixturesByUrl["/user_badges"]) - ); - this.delete("/user_badges/:badge_id", success); - - this.post("/posts", function(request) { - const data = parsePostData(request.requestBody); - - if (data.title === "this title triggers an error") { - return response(422, { errors: ["That title has already been taken"] }); - } - - if (data.raw === "enqueue this content please") { - return response(200, { - success: true, - action: "enqueued", - pending_post: { - id: 1234, - raw: data.raw - } - }); - } - - if (data.raw === "custom message") { - return response(200, { - success: true, - action: "custom", - message: "This is a custom response", - route_to: "/faq" - }); - } - - return response(200, { - success: true, - action: "create_post", - post: { - id: 12345, - topic_id: 280, - topic_slug: "internationalization-localization" - } - }); - }); - - this.post("/topics/timings", () => response(200, {})); - - const siteText = { id: "site.test", value: "Test McTest" }; - const overridden = { - id: "site.overridden", - value: "Overridden", - overridden: true - }; - - this.get("/admin/users/list/active.json", request => { - let store = [ - { - id: 1, - username: "eviltrout", - email: "eviltrout@example.com" - }, - { - id: 3, - username: "discobot", - email: "discobot_email" - } - ]; - - const showEmails = request.queryParams.show_emails; - - if (showEmails === "false") { - store = store.map(item => { - delete item.email; - return item; - }); - } - - const ascending = request.queryParams.ascending; - const order = request.queryParams.order; - - if (order) { - store = store.sort(function(a, b) { - return a[order] - b[order]; - }); - } - - if (ascending) { - store = store.reverse(); - } - - return response(200, store); - }); - - this.get("/admin/users/list/suspect.json", () => { - return response(200, [ - { - id: 2, - username: "sam", - email: "sam@example.com" - } - ]); - }); - - this.get("/admin/customize/site_texts", request => { - if (request.queryParams.overridden) { - return response(200, { site_texts: [overridden] }); - } else { - return response(200, { site_texts: [siteText, overridden] }); - } - }); - - this.get("/admin/customize/site_texts/:key", () => - response(200, { site_text: siteText }) - ); - this.delete("/admin/customize/site_texts/:key", () => - response(200, { site_text: siteText }) - ); - - this.put("/admin/customize/site_texts/:key", request => { - const result = parsePostData(request.requestBody); - result.id = request.params.key; - result.can_revert = true; - return response(200, { site_text: result }); - }); - - this.get("/tag_groups", () => response(200, { tag_groups: [] })); - - this.get("/admin/users/1234.json", () => { - return response(200, { - id: 1234, - username: "regular" - }); - }); - - this.get("/admin/users/1.json", () => { - return response(200, { - id: 1, - username: "eviltrout", - admin: true - }); - }); - - this.get("/admin/users/2.json", () => { - return response(200, { - id: 2, - username: "sam", - admin: true - }); - }); - - this.delete("/admin/users/:user_id.json", () => - response(200, { deleted: true }) - ); - this.post("/admin/badges", success); - this.delete("/admin/badges/:id", success); - - this.get("/admin/logs/staff_action_logs.json", () => { - return response(200, { - staff_action_logs: [], - extras: { user_history_actions: [] } - }); - }); - - this.get("/admin/logs/watched_words", () => { - return response(200, fixturesByUrl["/admin/logs/watched_words.json"]); - }); - this.delete("/admin/logs/watched_words/:id.json", success); - - this.post("/admin/logs/watched_words.json", request => { - const result = parsePostData(request.requestBody); - result.id = new Date().getTime(); - return response(200, result); - }); - - this.get("/admin/logs/search_logs.json", () => { - return response(200, [ - { term: "foobar", searches: 35, click_through: 6, unique: 16 } - ]); - }); - - this.get("/admin/logs/search_logs/term.json", () => { - return response(200, { - term: { - type: "search_log_term", - title: "Search Count", - term: "ruby", - data: [{ x: "2017-07-20", y: 2 }] - } - }); - }); - - this.post("/uploads/lookup-metadata", () => { - return response(200, { - imageFilename: "somefile.png", - imageFilesize: "10 KB", - imageWidth: "1", - imageHeight: "1" - }); - }); - - this.get("/inline-onebox", request => { - if ( - request.queryParams.urls.includes( - "http://www.example.com/has-title.html" - ) - ) { - return [ - 200, - { "Content-Type": "application/html" }, - '{"inline-oneboxes":[{"url":"http://www.example.com/has-title.html","title":"This is a great title"}]}' - ]; - } - }); - - this.get("/onebox", request => { - if ( - request.queryParams.url === "http://www.example.com/has-title.html" || - request.queryParams.url === - "http://www.example.com/has-title-and-a-url-that-is-more-than-80-characters-because-thats-good-for-seo-i-guess.html" - ) { - return [ - 200, - { "Content-Type": "application/html" }, - '' - ]; - } - - if (request.queryParams.url === "http://www.example.com/no-title.html") { - return [ - 200, - { "Content-Type": "application/html" }, - '' - ]; - } - - if (request.queryParams.url.indexOf("/internal-page.html") > -1) { - return [ - 200, - { "Content-Type": "application/html" }, - '' - ]; - } - - return [404, { "Content-Type": "application/html" }, ""]; + }, + badges: [{ id: 444, count: 1 }], + topics: [{ id: 1234, title: "cool title", url: "/t/1234/cool-title" }] }); }); - server.prepareBody = function(body) { - if (body && typeof body === "object") { - return JSON.stringify(body); + pretender.get("/u/eviltrout/invited_count.json", () => { + return response({ + counts: { pending: 1, redeemed: 0, total: 0 } + }); + }); + + pretender.get("/u/eviltrout/invited.json", () => { + return response({ invites: [{ id: 1 }] }); + }); + + pretender.get("/topics/private-messages/eviltrout.json", () => { + return response(fixturesByUrl["/topics/private-messages/eviltrout.json"]); + }); + + pretender.get("/topics/feature_stats.json", () => { + return response({ + pinned_in_category_count: 0, + pinned_globally_count: 0, + banner_count: 0 + }); + }); + + pretender.put("/t/34/convert-topic/public", () => { + return response({}); + }); + + pretender.put("/t/280/make-banner", () => { + return response({}); + }); + + pretender.put("/t/internationalization-localization/280/status", () => { + return response({ + success: "OK", + topic_status_update: null + }); + }); + + pretender.post("/clicks/track", success); + + pretender.get("/search", request => { + if (request.queryParams.q === "posts") { + return response({ + posts: [ + { + id: 1234 + } + ] + }); + } else if (request.queryParams.q === "evil") { + return response({ + posts: [ + { + id: 1234 + } + ], + tags: [ + { + id: 6, + name: "eviltrout" + } + ] + }); } - return body; + + return response({}); + }); + + pretender.put("/u/eviltrout.json", () => response({ user: {} })); + + pretender.get("/t/280.json", () => response(fixturesByUrl["/t/280/1.json"])); + pretender.get("/t/34.json", () => response(fixturesByUrl["/t/34/1.json"])); + pretender.get("/t/280/:post_number.json", () => + response(fixturesByUrl["/t/280/1.json"]) + ); + pretender.get("/t/28830.json", () => + response(fixturesByUrl["/t/28830/1.json"]) + ); + pretender.get("/t/9.json", () => response(fixturesByUrl["/t/9/1.json"])); + pretender.get("/t/12.json", () => response(fixturesByUrl["/t/12/1.json"])); + pretender.put("/t/1234/re-pin", success); + + pretender.get("/t/id_for/:slug", () => { + return response({ + id: 280, + slug: "internationalization-localization", + url: "/t/internationalization-localization/280" + }); + }); + + pretender.delete("/t/:id", success); + pretender.put("/t/:id/recover", success); + pretender.put("/t/:id/publish", success); + + pretender.get("/404-body", () => { + return [ + 200, + { "Content-Type": "text/html" }, + "
not found
" + ]; + }); + + pretender.delete("/draft.json", success); + pretender.post("/draft.json", success); + + pretender.get("/u/:username/staff-info.json", () => response({})); + + pretender.get("/post_action_users", () => { + return response({ + post_action_users: [ + { + id: 1, + username: "eviltrout", + avatar_template: "/user_avatar/default/eviltrout/{size}/1.png", + username_lower: "eviltrout" + } + ] + }); + }); + + pretender.get("/post_replies", () => { + return response({ post_replies: [{ id: 1234, cooked: "wat" }] }); + }); + + pretender.get("/post_reply_histories", () => { + return response({ post_reply_histories: [{ id: 1234, cooked: "wat" }] }); + }); + + pretender.get("/category_hashtags/check", () => { + return response({ valid: [{ slug: "bug", url: "/c/bugs" }] }); + }); + + pretender.get("/categories_and_latest", () => + response(fixturesByUrl["/categories_and_latest.json"]) + ); + + pretender.put("/categories/:category_id", request => { + const category = parsePostData(request.requestBody); + category.id = parseInt(request.params.category_id, 10); + + if (category.email_in === "duplicate@example.com") { + return response(422, { errors: ["duplicate email"] }); + } + + return response({ category }); + }); + + pretender.get("/draft.json", request => { + if (request.queryParams.draft_key === "new_topic") { + return response(fixturesByUrl["/draft.json"]); + } else if (request.queryParams.draft_key.startsWith("topic_")) + return response( + fixturesByUrl[request.url] || { + draft: null, + draft_sequence: 0 + } + ); + return response({}); + }); + + pretender.get("/drafts.json", () => response(fixturesByUrl["/drafts.json"])); + + pretender.put("/queued_posts/:queued_post_id", function(request) { + return response({ queued_post: { id: request.params.queued_post_id } }); + }); + + pretender.get("/queued_posts", function() { + return response({ + queued_posts: [{ id: 1, raw: "queued post text", can_delete_user: true }] + }); + }); + + pretender.post("/session", function(request) { + const data = parsePostData(request.requestBody); + + if (data.password === "correct") { + return response({ username: "eviltrout" }); + } + + if (data.password === "not-activated") { + return response({ + error: "not active", + reason: "not_activated", + sent_to_email: "eviltrout@example.com", + current_email: "current@example.com" + }); + } + + if (data.password === "not-activated-edit") { + return response({ + error: "not active", + reason: "not_activated", + sent_to_email: "eviltrout@example.com", + current_email: "current@example.com" + }); + } + + if (data.password === "need-second-factor") { + if (data.second_factor_token && data.second_factor_token === "123456") { + return response({ username: "eviltrout" }); + } + + return response({ + failed: "FAILED", + ok: false, + error: "Invalid authentication code. Each code can only be used once.", + reason: "invalid_second_factor", + backup_enabled: true, + security_key_enabled: false, + totp_enabled: true, + multiple_second_factor_methods: false + }); + } + + if (data.password === "need-security-key") { + if (data.securityKeyCredential) { + return response({ username: "eviltrout" }); + } + + return response({ + failed: "FAILED", + ok: false, + error: + "The selected second factor method is not enabled for your account.", + reason: "not_enabled_second_factor_method", + backup_enabled: false, + security_key_enabled: true, + totp_enabled: false, + multiple_second_factor_methods: false, + allowed_credential_ids: ["allowed_credential_ids"], + challenge: "challenge" + }); + } + + return response(400, { error: "invalid login" }); + }); + + pretender.post("/u/action/send_activation_email", success); + pretender.put("/u/update-activation-email", success); + + pretender.get("/u/hp.json", function() { + return response({ + value: "32faff1b1ef1ac3", + challenge: "61a3de0ccf086fb9604b76e884d75801" + }); + }); + + pretender.get("/session/csrf", function() { + return response({ csrf: "mgk906YLagHo2gOgM1ddYjAN4hQolBdJCqlY6jYzAYs=" }); + }); + + pretender.get("/groups/check-name", () => { + return response({ available: true }); + }); + + pretender.get("/u/check_username", function(request) { + if (request.queryParams.username === "taken") { + return response({ available: false, suggestion: "nottaken" }); + } + return response({ available: true }); + }); + + pretender.post("/u", () => response({ success: true })); + + pretender.get("/login.html", () => [200, {}, "LOGIN PAGE"]); + + pretender.delete("/posts/:post_id", success); + pretender.put("/posts/:post_id/recover", success); + pretender.get("/posts/:post_id/expand-embed", success); + + pretender.put("/posts/:post_id", request => { + const data = parsePostData(request.requestBody); + if (data.post.raw === "this will 409") { + return [ + 409, + { "Content-Type": "application/json" }, + { errors: ["edit conflict"] } + ]; + } + data.post.id = request.params.post_id; + data.post.version = 2; + return response(200, data.post); + }); + + pretender.get("/t/403.json", () => response(403, {})); + pretender.get("/t/404.json", () => response(404, "not found")); + pretender.get("/t/500.json", () => response(502, {})); + + pretender.put("/t/:slug/:id", request => { + const isJSON = request.requestHeaders["Content-Type"].includes( + "application/json" + ); + + const data = isJSON + ? JSON.parse(request.requestBody) + : parsePostData(request.requestBody); + + return response(200, { + basic_topic: { + id: request.params.id, + title: data.title, + fancy_title: data.title, + slug: request.params.slug + } + }); + }); + + pretender.get("groups", () => { + return response(200, fixturesByUrl["/groups.json"]); + }); + + pretender.get("/groups.json", () => { + return response(200, fixturesByUrl["/groups.json?username=eviltrout"]); + }); + + pretender.get("groups/search.json", () => { + return response(200, []); + }); + + pretender.get("/topics/groups/discourse.json", () => { + return response(200, fixturesByUrl["/topics/groups/discourse.json"]); + }); + + pretender.get("/groups/discourse/mentions.json", () => { + return response(200, fixturesByUrl["/groups/discourse/posts.json"]); + }); + + pretender.get("/groups/discourse/messages.json", () => { + return response(200, fixturesByUrl["/groups/discourse/posts.json"]); + }); + + pretender.get("/groups/moderators/members.json", () => { + return response(200, fixturesByUrl["/groups/discourse/members.json"]); + }); + + pretender.get("/t/:topic_id/posts.json", request => { + const postIds = request.queryParams.post_ids; + const postNumber = parseInt(request.queryParams.post_number, 10); + let posts; + + if (postIds) { + posts = postIds.map(p => ({ + id: parseInt(p, 10), + post_number: parseInt(p, 10) + })); + } else if (postNumber && request.queryParams.asc === "true") { + posts = _.range(postNumber + 1, postNumber + 6).map(p => ({ + id: parseInt(p, 10), + post_number: parseInt(p, 10) + })); + } else if (postNumber && request.queryParams.asc === "false") { + posts = _.range(postNumber - 5, postNumber) + .reverse() + .map(p => ({ + id: parseInt(p, 10), + post_number: parseInt(p, 10) + })); + } + + return response(200, { post_stream: { posts } }); + }); + + pretender.get("/posts/:post_id/reply-history.json", () => { + return response(200, [{ id: 2222, post_number: 2222 }]); + }); + + pretender.get("/posts/:post_id/reply-ids.json", () => { + return response(200, { + direct_reply_ids: [45], + all_reply_ids: [45, 100] + }); + }); + + pretender.post("/user_badges", () => + response(200, fixturesByUrl["/user_badges"]) + ); + pretender.delete("/user_badges/:badge_id", success); + + pretender.post("/posts", function(request) { + const data = parsePostData(request.requestBody); + + if (data.title === "this title triggers an error") { + return response(422, { errors: ["That title has already been taken"] }); + } + + if (data.raw === "enqueue this content please") { + return response(200, { + success: true, + action: "enqueued", + pending_post: { + id: 1234, + raw: data.raw + } + }); + } + + if (data.raw === "custom message") { + return response(200, { + success: true, + action: "custom", + message: "This is a custom response", + route_to: "/faq" + }); + } + + return response(200, { + success: true, + action: "create_post", + post: { + id: 12345, + topic_id: 280, + topic_slug: "internationalization-localization" + } + }); + }); + + pretender.post("/topics/timings", () => response(200, {})); + + const siteText = { id: "site.test", value: "Test McTest" }; + const overridden = { + id: "site.overridden", + value: "Overridden", + overridden: true }; - server.unhandledRequest = function(verb, path) { - const error = - "Unhandled request in test environment: " + path + " (" + verb + ")"; - window.console.error(error); - throw error; - }; + pretender.get("/admin/users/list/active.json", request => { + let store = [ + { + id: 1, + username: "eviltrout", + email: "eviltrout@example.com" + }, + { + id: 3, + username: "discobot", + email: "discobot_email" + } + ]; - server.checkPassthrough = request => - request.requestHeaders["Discourse-Script"]; - return server; + const showEmails = request.queryParams.show_emails; + + if (showEmails === "false") { + store = store.map(item => { + delete item.email; + return item; + }); + } + + const ascending = request.queryParams.ascending; + const order = request.queryParams.order; + + if (order) { + store = store.sort(function(a, b) { + return a[order] - b[order]; + }); + } + + if (ascending) { + store = store.reverse(); + } + + return response(200, store); + }); + + pretender.get("/admin/users/list/suspect.json", () => { + return response(200, [ + { + id: 2, + username: "sam", + email: "sam@example.com" + } + ]); + }); + + pretender.get("/admin/customize/site_texts", request => { + if (request.queryParams.overridden) { + return response(200, { site_texts: [overridden] }); + } else { + return response(200, { site_texts: [siteText, overridden] }); + } + }); + + pretender.get("/admin/customize/site_texts/:key", () => + response(200, { site_text: siteText }) + ); + pretender.delete("/admin/customize/site_texts/:key", () => + response(200, { site_text: siteText }) + ); + + pretender.put("/admin/customize/site_texts/:key", request => { + const result = parsePostData(request.requestBody); + result.id = request.params.key; + result.can_revert = true; + return response(200, { site_text: result }); + }); + + pretender.get("/tag_groups", () => response(200, { tag_groups: [] })); + + pretender.get("/admin/users/1.json", () => { + return response(200, { + id: 1, + username: "eviltrout", + email: "eviltrout@example.com", + admin: true + }); + }); + + pretender.get("/admin/users/2.json", () => { + return response(200, { + id: 2, + username: "sam", + admin: true + }); + }); + + pretender.get("/admin/users/3.json", () => { + return response(200, { + id: 3, + username: "markvanlan", + email: "markvanlan@example.com", + secondary_emails: ["markvanlan1@example.com", "markvanlan2@example.com"] + }); + }); + + pretender.get("/admin/users/1234.json", () => { + return response(200, { + id: 1234, + username: "regular" + }); + }); + + pretender.get("/admin/users/1235.json", () => { + return response(200, { + id: 1235, + username: "regular2" + }); + }); + + pretender.delete("/admin/users/:user_id.json", () => + response(200, { deleted: true }) + ); + pretender.post("/admin/badges", success); + pretender.delete("/admin/badges/:id", success); + + pretender.get("/admin/logs/staff_action_logs.json", () => { + return response(200, { + staff_action_logs: [], + extras: { user_history_actions: [] } + }); + }); + + pretender.get("/admin/logs/watched_words", () => { + return response(200, fixturesByUrl["/admin/logs/watched_words.json"]); + }); + pretender.delete("/admin/logs/watched_words/:id.json", success); + + pretender.post("/admin/logs/watched_words.json", request => { + const result = parsePostData(request.requestBody); + result.id = new Date().getTime(); + return response(200, result); + }); + + pretender.get("/admin/logs/search_logs.json", () => { + return response(200, [ + { term: "foobar", searches: 35, click_through: 6, unique: 16 } + ]); + }); + + pretender.get("/admin/logs/search_logs/term.json", () => { + return response(200, { + term: { + type: "search_log_term", + title: "Search Count", + term: "ruby", + data: [{ x: "2017-07-20", y: 2 }] + } + }); + }); + + pretender.post("/uploads/lookup-metadata", () => { + return response(200, { + imageFilename: "somefile.png", + imageFilesize: "10 KB", + imageWidth: "1", + imageHeight: "1" + }); + }); + + pretender.get("/inline-onebox", request => { + if ( + request.queryParams.urls.includes("http://www.example.com/has-title.html") + ) { + return [ + 200, + { "Content-Type": "application/html" }, + '{"inline-oneboxes":[{"url":"http://www.example.com/has-title.html","title":"This is a great title"}]}' + ]; + } + }); + + pretender.get("/onebox", request => { + if ( + request.queryParams.url === "http://www.example.com/has-title.html" || + request.queryParams.url === + "http://www.example.com/has-title-and-a-url-that-is-more-than-80-characters-because-thats-good-for-seo-i-guess.html" + ) { + return [ + 200, + { "Content-Type": "application/html" }, + '' + ]; + } + + if (request.queryParams.url === "http://www.example.com/no-title.html") { + return [ + 200, + { "Content-Type": "application/html" }, + '' + ]; + } + + if (request.queryParams.url.indexOf("/internal-page.html") > -1) { + return [ + 200, + { "Content-Type": "application/html" }, + '' + ]; + } + if (request.queryParams.url === "http://somegoodurl.com/") { + return [ + 200, + { "Content-Type": "application/html" }, + ` + + ` + ]; + } + return [404, { "Content-Type": "application/html" }, ""]; + }); } diff --git a/test/javascripts/lib/click-track-edit-history-test.js.es6 b/test/javascripts/lib/click-track-edit-history-test.js.es6 index 745d7d195c..ae8f6d18c2 100644 --- a/test/javascripts/lib/click-track-edit-history-test.js.es6 +++ b/test/javascripts/lib/click-track-edit-history-test.js.es6 @@ -2,6 +2,7 @@ import DiscourseURL from "discourse/lib/url"; import ClickTrack from "discourse/lib/click-track"; import { fixture, logIn } from "helpers/qunit-helpers"; import User from "discourse/models/user"; +import pretender from "helpers/create-pretender"; QUnit.module("lib:click-track-edit-history", { beforeEach() { @@ -62,8 +63,7 @@ QUnit.skip("tracks internal URLs", async assert => { sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com"); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.equal( request.requestBody, "url=http%3A%2F%2Fdiscuss.domain.com&post_id=42&topic_id=1337" @@ -78,8 +78,7 @@ QUnit.skip("tracks external URLs", async assert => { assert.expect(2); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.equal( request.requestBody, "url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337" @@ -97,8 +96,7 @@ QUnit.skip( User.currentProp("external_links_in_new_tab", true); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.equal( request.requestBody, "url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337" diff --git a/test/javascripts/lib/click-track-profile-page-test.js.es6 b/test/javascripts/lib/click-track-profile-page-test.js.es6 index a1cc164013..d46027a9d2 100644 --- a/test/javascripts/lib/click-track-profile-page-test.js.es6 +++ b/test/javascripts/lib/click-track-profile-page-test.js.es6 @@ -1,6 +1,7 @@ import DiscourseURL from "discourse/lib/url"; import ClickTrack from "discourse/lib/click-track"; import { fixture, logIn } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; QUnit.module("lib:click-track-profile-page", { beforeEach() { @@ -55,8 +56,7 @@ QUnit.skip("tracks internal URLs", async assert => { sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com"); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.equal(request.requestBody, "url=http%3A%2F%2Fdiscuss.domain.com"); done(); }); @@ -68,8 +68,7 @@ QUnit.skip("tracks external URLs", async assert => { assert.expect(2); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.equal( request.requestBody, "url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337" @@ -84,8 +83,7 @@ QUnit.skip("tracks external URLs in other posts", async assert => { assert.expect(2); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.equal( request.requestBody, "url=http%3A%2F%2Fwww.google.com&post_id=24&topic_id=7331" diff --git a/test/javascripts/lib/click-track-test.js.es6 b/test/javascripts/lib/click-track-test.js.es6 index 7dd0747e72..7d5167ce2f 100644 --- a/test/javascripts/lib/click-track-test.js.es6 +++ b/test/javascripts/lib/click-track-test.js.es6 @@ -3,6 +3,7 @@ import DiscourseURL from "discourse/lib/url"; import ClickTrack from "discourse/lib/click-track"; import { fixture, logIn } from "helpers/qunit-helpers"; import User from "discourse/models/user"; +import pretender from "helpers/create-pretender"; QUnit.module("lib:click-track", { beforeEach() { @@ -55,8 +56,7 @@ QUnit.skip("tracks internal URLs", async assert => { sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com"); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.ok( request.requestBody, "url=http%3A%2F%2Fdiscuss.domain.com&post_id=42&topic_id=1337" @@ -74,8 +74,7 @@ QUnit.skip("does not track elements with no href", async assert => { QUnit.skip("does not track attachments", async assert => { sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com"); - /* global server */ - server.post("/clicks/track", () => assert.ok(false)); + pretender.post("/clicks/track", () => assert.ok(false)); assert.notOk(track(generateClickEventOn(".attachment"))); assert.ok( @@ -89,8 +88,7 @@ QUnit.skip("tracks external URLs", async assert => { assert.expect(2); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.ok( request.requestBody, "url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337" @@ -108,8 +106,7 @@ QUnit.skip( User.currentProp("external_links_in_new_tab", true); const done = assert.async(); - /* global server */ - server.post("/clicks/track", request => { + pretender.post("/clicks/track", request => { assert.ok( request.requestBody, "url=http%3A%2F%2Fwww.google.com&post_id=42&topic_id=1337" diff --git a/test/javascripts/lib/link-mentions-test.js.es6 b/test/javascripts/lib/link-mentions-test.js.es6 index 46bdefa423..a7c309cbbb 100644 --- a/test/javascripts/lib/link-mentions-test.js.es6 +++ b/test/javascripts/lib/link-mentions-test.js.es6 @@ -3,12 +3,12 @@ import { linkSeenMentions } from "discourse/lib/link-mentions"; import { Promise } from "rsvp"; +import pretender from "helpers/create-pretender"; QUnit.module("lib:link-mentions"); QUnit.test("linkSeenMentions replaces users and groups", async assert => { - /* global server */ - server.get("/u/is_local_username", () => [ + pretender.get("/u/is_local_username", () => [ 200, { "Content-Type": "application/json" }, { diff --git a/test/javascripts/lib/oneboxer-test.js.es6 b/test/javascripts/lib/oneboxer-test.js.es6 index 77ca103827..22e86e97df 100644 --- a/test/javascripts/lib/oneboxer-test.js.es6 +++ b/test/javascripts/lib/oneboxer-test.js.es6 @@ -20,11 +20,6 @@ QUnit.test("load - failed onebox", async assert => { let element = document.createElement("A"); element.setAttribute("href", "http://somebadurl.com"); - // prettier-ignore - server.get("/onebox", () => { //eslint-disable-line - return [404, {}, {}]; - }); - await loadOnebox(element); assert.equal( @@ -55,11 +50,6 @@ QUnit.test("load - successful onebox", async assert => { `; - // prettier-ignore - server.get("/onebox", () => { //eslint-disable-line - return [200, {}, html]; - }); - let element = document.createElement("A"); element.setAttribute("href", "http://somegoodurl.com"); @@ -72,7 +62,7 @@ QUnit.test("load - successful onebox", async assert => { ); assert.equal( loadOnebox(element), - stringToHTML(html).outerHTML, + html.trim(), "it returns the html from the cache" ); }); diff --git a/test/javascripts/lib/screen-track-test.js.es6 b/test/javascripts/lib/screen-track-test.js.es6 index 2fb7df9497..9574e972a7 100644 --- a/test/javascripts/lib/screen-track-test.js.es6 +++ b/test/javascripts/lib/screen-track-test.js.es6 @@ -1,6 +1,7 @@ import TopicTrackingState from "discourse/models/topic-tracking-state"; import Session from "discourse/models/session"; import ScreenTrack from "discourse/lib/screen-track"; +import pretender from "helpers/create-pretender"; let clock; @@ -18,8 +19,7 @@ QUnit.module("lib:screen-track", { QUnit.skip("Correctly flushes posts as needed", assert => { const timings = []; - // prettier-ignore - server.post("/topics/timings", t => { //eslint-disable-line + pretender.post("/topics/timings", t => { timings.push(t); return [200, {}, ""]; }); diff --git a/test/javascripts/lib/upload-short-url-test.js.es6 b/test/javascripts/lib/upload-short-url-test.js.es6 index f969e64878..39a5e7b000 100644 --- a/test/javascripts/lib/upload-short-url-test.js.es6 +++ b/test/javascripts/lib/upload-short-url-test.js.es6 @@ -5,6 +5,7 @@ import { } from "pretty-text/upload-short-url"; import { ajax } from "discourse/lib/ajax"; import { fixture } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; QUnit.module("lib:pretty-text/upload-short-url", { beforeEach() { @@ -46,8 +47,7 @@ QUnit.module("lib:pretty-text/upload-short-url", { } ]; - // prettier-ignore - server.post("/uploads/lookup-urls", () => { //eslint-disable-line + pretender.post("/uploads/lookup-urls", () => { return response(imageSrcs.concat(attachmentSrcs.concat(otherMediaSrcs))); }); diff --git a/test/javascripts/lib/user-search-test.js.es6 b/test/javascripts/lib/user-search-test.js.es6 index c93a87564d..79e11587f0 100644 --- a/test/javascripts/lib/user-search-test.js.es6 +++ b/test/javascripts/lib/user-search-test.js.es6 @@ -1,5 +1,6 @@ import userSearch from "discourse/lib/user-search"; import { CANCELLED_STATUS } from "discourse/lib/autocomplete"; +import pretender from "helpers/create-pretender"; QUnit.module("lib:user-search", { beforeEach() { @@ -7,13 +8,11 @@ QUnit.module("lib:user-search", { return [200, { "Content-Type": "application/json" }, object]; }; - // prettier-ignore - server.get("/u/search/users", request => { //eslint-disable-line - + pretender.get("/u/search/users", request => { // special responder for per category search const categoryMatch = request.url.match(/category_id=([0-9]+)/); if (categoryMatch) { - if(categoryMatch[1] === "3"){ + if (categoryMatch[1] === "3") { return response({}); } return response({ @@ -24,11 +23,12 @@ QUnit.module("lib:user-search", { avatar_template: "https://avatars.discourse.org/v3/letter/t/41988e/{size}.png" } - ]}); + ] + }); } - if(request.url.match(/no-results/)){ - return response({users: []}); + if (request.url.match(/no-results/)) { + return response({ users: [] }); } return response({ diff --git a/test/javascripts/models/post-stream-test.js.es6 b/test/javascripts/models/post-stream-test.js.es6 index 2276014241..9ba4632041 100644 --- a/test/javascripts/models/post-stream-test.js.es6 +++ b/test/javascripts/models/post-stream-test.js.es6 @@ -2,6 +2,7 @@ import Post from "discourse/models/post"; import createStore from "helpers/create-store"; import User from "discourse/models/user"; import { Promise } from "rsvp"; +import pretender from "helpers/create-pretender"; QUnit.module("model:post-stream"); @@ -753,8 +754,7 @@ QUnit.test("triggerRecoveredPost", async assert => { return [200, { "Content-Type": "application/json" }, object]; }; - // prettier-ignore - server.get("/posts/4", () => { // eslint-disable-line no-undef + pretender.get("/posts/4", () => { return response({ id: 4, post_number: 4 }); }); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index f005b678ab..c2c3520a3b 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -1,5 +1,4 @@ /*global document, sinon, QUnit, Logster */ - //= require env //= require jquery.debug //= require jquery.ui.widget @@ -77,7 +76,7 @@ if (window.Logster) { window.Logster = { enabled: false }; } -var pretender = require("helpers/create-pretender", null, null, false), +var createPretender = require("helpers/create-pretender", null, null, false), fixtures = require("fixtures/site-fixtures", null, null, false).default, flushMap = require("discourse/models/store", null, null, false).flushMap, ScrollingDOMMethods = require("discourse/mixins/scrolling", null, null, false) @@ -102,13 +101,32 @@ function resetSite(siteSettings, extras) { } QUnit.testStart(function(ctx) { - server = pretender.default(); + server = createPretender.default; + createPretender.applyDefaultHandlers(server); + server.handlers = [] + + server.prepareBody = function(body) { + if (body && typeof body === "object") { + return JSON.stringify(body); + } + return body; + }; + + server.unhandledRequest = function(verb, path) { + const error = + "Unhandled request in test environment: " + path + " (" + verb + ")"; + window.console.error(error); + throw error; + }; + + server.checkPassthrough = request => + request.requestHeaders["Discourse-Script"]; if (ctx.module.startsWith(acceptanceModulePrefix)) { var helper = { - parsePostData: pretender.parsePostData, - response: pretender.response, - success: pretender.success + parsePostData: createPretender.parsePostData, + response: createPretender.response, + success: createPretender.success }; applyPretender( @@ -153,10 +171,6 @@ QUnit.testDone(function() { $(".modal-backdrop").remove(); flushMap(); - server.shutdown(); - - window.server = null; - // ensures any event not removed is not leaking between tests // most likely in intialisers, other places (controller, component...) // should be fixed in code From f17459c6204717555aa7f021ad9b6d74b0c4a428 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Mon, 2 Mar 2020 20:27:50 +0100 Subject: [PATCH 0050/1830] UX: attempts to increate popup menu hitzone on mobile (#9038) --- app/assets/stylesheets/mobile/topic-post.scss | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index 30b2f6d976..1d37052b88 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -476,10 +476,20 @@ span.highlighted { } } -.popup-menu { +.popup-menu, +#topic-footer-buttons .popup-menu { h3 { margin-bottom: 0; } + + ul div li { + border-bottom: 0.25em solid transparent; + border-top: 0.25em solid transparent; + + button.btn { + margin-bottom: 0; + } + } } .post-notice { From a653737a6656c82c821d7506b6e38bd9e9679b45 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 2 Mar 2020 14:28:54 -0500 Subject: [PATCH 0051/1830] FIX: Add aria-labels to topic list items (#9048) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FIX: Add aria-labels to topic list items Before this fix you could navigate the topic list using a screen reader and a keyboard but some of the items were not as descriptive as they could be. The newly added labels make it easier to understand what you are tabbing over. context: https://meta.discourse.org/t/accessibility-aria-attributes-are-not-defined-for-links-under-replies-category/142539 * Update app/assets/javascripts/discourse/lib/utilities.js.es6 Co-Authored-By: Régis Hanol * Multiline fix * Fix more tests Co-authored-by: Régis Hanol --- .../javascripts/discourse/helpers/application.js.es6 | 5 +++++ app/assets/javascripts/discourse/lib/utilities.js.es6 | 9 ++++++--- .../discourse/templates/list/posts-count-column.hbr | 2 +- test/javascripts/lib/utilities-test.js.es6 | 2 +- test/javascripts/models/report-test.js.es6 | 4 ++-- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/discourse/helpers/application.js.es6 b/app/assets/javascripts/discourse/helpers/application.js.es6 index e6a88ded97..71baa92c91 100644 --- a/app/assets/javascripts/discourse/helpers/application.js.es6 +++ b/app/assets/javascripts/discourse/helpers/application.js.es6 @@ -41,6 +41,11 @@ registerUnbound("number", (orig, params) => { if (n.toString() !== title.toString() && addTitle) { result += " title='" + Handlebars.Utils.escapeExpression(title) + "'"; } + if (params.ariaLabel) { + const ariaLabel = Handlebars.Utils.escapeExpression(params.ariaLabel); + result += ` aria-label='${ariaLabel}'`; + } + result += ">" + n + ""; return new safe(result); diff --git a/app/assets/javascripts/discourse/lib/utilities.js.es6 b/app/assets/javascripts/discourse/lib/utilities.js.es6 index 8b210b4737..e44a60d53a 100644 --- a/app/assets/javascripts/discourse/lib/utilities.js.es6 +++ b/app/assets/javascripts/discourse/lib/utilities.js.es6 @@ -66,9 +66,12 @@ export function avatarImg(options, getURL) { const classes = "avatar" + (options.extraClasses ? " " + options.extraClasses : ""); - const title = options.title - ? " title='" + escapeExpression(options.title || "") + "'" - : ""; + + let title = ""; + if (options.title) { + const escaped = escapeExpression(options.title || ""); + title = ` title='${escaped}' aria-label='${escaped}'`; + } return ( " {{raw-plugin-outlet name="topic-list-before-reply-count"}} - {{number topic.replyCount noTitle="true"}} + {{number topic.replyCount noTitle="true" ariaLabel=view.title}} diff --git a/test/javascripts/lib/utilities-test.js.es6 b/test/javascripts/lib/utilities-test.js.es6 index dd34d8a204..46609895a2 100644 --- a/test/javascripts/lib/utilities-test.js.es6 +++ b/test/javascripts/lib/utilities-test.js.es6 @@ -89,7 +89,7 @@ QUnit.test("avatarImg", assert => { size: "tiny", title: "evilest trout" }), - "", + "", "it adds a title if supplied" ); diff --git a/test/javascripts/models/report-test.js.es6 b/test/javascripts/models/report-test.js.es6 index 1fa622a1d3..821a88eee8 100644 --- a/test/javascripts/models/report-test.js.es6 +++ b/test/javascripts/models/report-test.js.es6 @@ -459,7 +459,7 @@ QUnit.test("computed labels", assert => { const computedUsernameLabel = usernameLabel.compute(row); assert.equal( computedUsernameLabel.formatedValue, - "joffrey" + "joffrey" ); assert.equal(computedUsernameLabel.value, "joffrey"); @@ -542,6 +542,6 @@ QUnit.test("computed labels", assert => { const userLink = computedLabels[0].compute(row).formatedValue; assert.equal( userLink, - "joffrey" + "joffrey" ); }); From c62d5b139ba08f5b995ba4979d419e8cfb28e132 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Mon, 2 Mar 2020 21:29:40 +0200 Subject: [PATCH 0052/1830] FIX: Allow users to create polls in PMs with non human users (#9055) --- .../advanced_user_narrative_spec.rb | 13 +++++++++++++ plugins/poll/lib/post_validator.rb | 2 +- .../spec/controllers/posts_controller_spec.rb | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb index a44c9e250c..28fec30417 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb @@ -606,6 +606,19 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do ) end + it 'allows new users to create polls' do + user.update(trust_level: 0) + + post = PostCreator.create(user, topic_id: topic.id, raw: <<~RAW) + [poll type=regular] + * foo + * bar + [/poll] + RAW + + expect(post.errors[:base].size).to eq(0) + end + describe 'when post is not in the right topic' do it 'should not do anything' do other_post diff --git a/plugins/poll/lib/post_validator.rb b/plugins/poll/lib/post_validator.rb index 19f6648e4f..788fe1e24b 100644 --- a/plugins/poll/lib/post_validator.rb +++ b/plugins/poll/lib/post_validator.rb @@ -9,7 +9,7 @@ module DiscoursePoll def validate_post min_trust_level = SiteSetting.poll_minimum_trust_level_to_create - if @post&.user&.staff? || @post&.user&.trust_level >= TrustLevel[min_trust_level] + if @post&.user&.staff? || @post&.user&.trust_level >= TrustLevel[min_trust_level] || @post&.topic&.pm_with_non_human_user? true else @post.errors.add(:base, I18n.t("poll.insufficient_rights_to_create")) diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb index 411247c8f7..8f9dae14a2 100644 --- a/plugins/poll/spec/controllers/posts_controller_spec.rb +++ b/plugins/poll/spec/controllers/posts_controller_spec.rb @@ -348,6 +348,23 @@ describe PostsController do json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.insufficient_rights_to_create")) end + + it "skips the check in PMs with bots" do + user = Fabricate(:user, trust_level: 1) + topic = Fabricate(:private_message_topic, topic_allowed_users: [ + Fabricate.build(:topic_allowed_user, user: user), + Fabricate.build(:topic_allowed_user, user: Discourse.system_user) + ]) + Fabricate(:post, topic_id: topic.id, user_id: Discourse::SYSTEM_USER_ID) + + log_in_user(user) + + post :create, params: { + topic_id: topic.id, raw: "[poll]\n- A\n- B\n[/poll]" + }, format: :json + + expect(::JSON.parse(response.body)["errors"]).to eq(nil) + end end describe "regular user with equal trust level" do From c11e5eb042303c4933ac1faefdd46064b4d2ff25 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Mon, 2 Mar 2020 13:30:23 -0600 Subject: [PATCH 0053/1830] DEV: Run prettier on staged files before commit using lefthook (#9064) * DEV: Run prettier on staged files before commit using lefthook * excluded some js files --- lefthook.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lefthook.yml b/lefthook.yml index f3305fb786..8dae834398 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -4,6 +4,10 @@ pre-commit: rubocop: glob: "*.rb" run: bundle exec rubocop {staged_files} + prettier: + glob: "*.{js,es6}" + exclude: "vendor/*|fixtures|public/javascripts|shims.js|ember-addons|template-lintrc|locale/*|test_helper|run-qunit" + run: yarn prettier --list-different {staged_files} eslint: glob: "*.{js,es6}" exclude: "vendor/*|fixtures|public/javascripts|shims.js|ember-addons|template-lintrc|locale/*|test_helper|run-qunit" From 11425f8adcfbce14d8f774a7768816ef1246c685 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Mon, 2 Mar 2020 20:30:51 +0100 Subject: [PATCH 0054/1830] FEATURE: alows to add a description link to a report (#9065) This commit adds a description link to users_per_trust_level report linking to our blog article on the subject https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/ --- app/assets/javascripts/admin/models/report.js.es6 | 2 ++ .../admin/templates/components/admin-report.hbs | 12 +++++++++--- app/controllers/admin/reports_controller.rb | 2 ++ app/models/report.rb | 3 +++ config/locales/server.en.yml | 1 + 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/admin/models/report.js.es6 b/app/assets/javascripts/admin/models/report.js.es6 index bd7074ced2..d0152c1a9e 100644 --- a/app/assets/javascripts/admin/models/report.js.es6 +++ b/app/assets/javascripts/admin/models/report.js.es6 @@ -21,6 +21,8 @@ const Report = EmberObject.extend({ average: false, percent: false, higher_is_better: true, + description_link: null, + description: null, @discourseComputed("type", "start_date", "end_date") reportUrl(type, start_date, end_date) { diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs index f8a36fa7d3..cb0f333bb0 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs @@ -23,9 +23,15 @@ {{#if model.description}} - - {{d-icon "question-circle"}} - + {{#if model.description_link}} + + {{d-icon "question-circle"}} + + {{else}} + + {{d-icon "question-circle"}} + + {{/if}} {{/if}} {{/unless}} diff --git a/app/controllers/admin/reports_controller.rb b/app/controllers/admin/reports_controller.rb index 864512c451..5fc2544b48 100644 --- a/app/controllers/admin/reports_controller.rb +++ b/app/controllers/admin/reports_controller.rb @@ -11,11 +11,13 @@ class Admin::ReportsController < Admin::AdminController reports = reports_methods.map do |name| type = name.to_s.gsub('report_', '') description = I18n.t("reports.#{type}.description", default: '') + description_link = I18n.t("reports.#{type}.description_link", default: '') { type: type, title: I18n.t("reports.#{type}.title"), description: description.presence ? description : nil, + description_link: description_link.presence ? description_link : nil } end diff --git a/app/models/report.rb b/app/models/report.rb index de17d8346f..13f7d02830 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -99,12 +99,15 @@ class Report def as_json(options = nil) description = I18n.t("reports.#{type}.description", default: "") + description_link = I18n.t("reports.#{type}.description_link", default: "") + { type: type, title: I18n.t("reports.#{type}.title", default: nil), xaxis: I18n.t("reports.#{type}.xaxis", default: nil), yaxis: I18n.t("reports.#{type}.yaxis", default: nil), description: description.presence ? description : nil, + description_link: description_link.presence ? description_link : nil, data: data, start_date: start_date&.iso8601, end_date: end_date&.iso8601, diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 00e24df01c..c4db42fb1c 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1175,6 +1175,7 @@ en: labels: level: Level description: "Number of users grouped by trust level." + description_link: "https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/" users_by_type: title: "Users per Type" xaxis: "Type" From b78df9c4c961c8c3a52f0797e567a168df4e34e6 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 14:31:06 -0500 Subject: [PATCH 0055/1830] Build(deps): Bump aws-sigv4 from 1.1.0 to 1.1.1 (#9067) Bumps [aws-sigv4](https://github.com/aws/aws-sdk-ruby) from 1.1.0 to 1.1.1. - [Release notes](https://github.com/aws/aws-sdk-ruby/releases) - [Changelog](https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sigv4/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-ruby/compare/1.1.0...1.1.1) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 18d6188199..abe2f0a885 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -61,7 +61,7 @@ GEM aws-sdk-sns (1.21.0) aws-sdk-core (~> 3, >= 3.71.0) aws-sigv4 (~> 1.1) - aws-sigv4 (1.1.0) + aws-sigv4 (1.1.1) aws-eventstream (~> 1.0, >= 1.0.2) barber (0.12.2) ember-source (>= 1.0, < 3.1) From f44ad91a529ddf6101698c82fc3bacaadefe0e73 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 14:31:19 -0500 Subject: [PATCH 0056/1830] Build(deps): Bump hashdiff from 1.0.0 to 1.0.1 (#9068) Bumps [hashdiff](https://github.com/liufengyun/hashdiff) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/liufengyun/hashdiff/releases) - [Changelog](https://github.com/liufengyun/hashdiff/blob/master/changelog.md) - [Commits](https://github.com/liufengyun/hashdiff/commits) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index abe2f0a885..8eaa96fb40 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -141,7 +141,7 @@ GEM globalid (0.4.2) activesupport (>= 4.2.0) guess_html_encoding (0.0.11) - hashdiff (1.0.0) + hashdiff (1.0.1) hashie (3.6.0) highline (1.7.10) hkdf (0.3.0) From 537f87562e71acb464e02fc81f2596b01816072c Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Mon, 2 Mar 2020 16:33:52 -0300 Subject: [PATCH 0057/1830] FIX: We need to skip users with associated reviewables when auto-approving (#9080) * FIX: We need to skip users with associated reviewables when auto-approving them * Update spec/initializers/track_setting_changes_spec.rb * Update spec/initializers/track_setting_changes_spec.rb Co-authored-by: Robin Ward --- .../initializers/014-track-setting-changes.rb | 5 +++- .../track_setting_changes_spec.rb | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 spec/initializers/track_setting_changes_spec.rb diff --git a/config/initializers/014-track-setting-changes.rb b/config/initializers/014-track-setting-changes.rb index f8276d9dcc..200f2c2da6 100644 --- a/config/initializers/014-track-setting-changes.rb +++ b/config/initializers/014-track-setting-changes.rb @@ -4,7 +4,10 @@ DiscourseEvent.on(:site_setting_changed) do |name, old_value, new_value| # Enabling `must_approve_users` on an existing site is odd, so we assume that the # existing users are approved. if name == :must_approve_users && new_value == true - User.where(approved: false).update_all(approved: true) + + User.where(approved: false) + .joins("LEFT JOIN reviewables r ON r.target_id = users.id") + .where(r: { id: nil }).update_all(approved: true) end if name == :emoji_set diff --git a/spec/initializers/track_setting_changes_spec.rb b/spec/initializers/track_setting_changes_spec.rb new file mode 100644 index 0000000000..82b7963ec4 --- /dev/null +++ b/spec/initializers/track_setting_changes_spec.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Setting changes' do + describe '#must_approve_users' do + before { SiteSetting.must_approve_users = false } + + it 'does not approve a user with associated reviewables' do + user_pending_approval = Fabricate(:reviewable_user).target + + SiteSetting.must_approve_users = true + + expect(user_pending_approval.reload.approved?).to eq(false) + end + + it 'approves a user with no associated reviewables' do + non_approved_user = Fabricate(:user, approved: false) + + SiteSetting.must_approve_users = true + + expect(non_approved_user.reload.approved?).to eq(true) + end + end +end From 4da357e3787c3627b26de0b56b7ab6e42c89496b Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Mon, 2 Mar 2020 21:20:19 +0100 Subject: [PATCH 0058/1830] DEV: Use async functions in tests (#9087) This change both improves readability and fixes potential race-condition issues where promises were nested instead of being chained. Also includes: * Use arrow functions and Promise shorthands * Remove the obsolete `asyncTestDiscourse` helper --- .../controllers/history-test.js.es6 | 10 +- test/javascripts/helpers/qunit-helpers.js.es6 | 11 -- test/javascripts/lib/load-script-test.js.es6 | 11 +- .../javascripts/lib/preload-store-test.js.es6 | 77 +++------ .../models/post-stream-test.js.es6 | 102 +++++------ test/javascripts/models/post-test.js.es6 | 30 ++-- .../javascripts/models/rest-model-test.js.es6 | 64 ++++--- .../javascripts/models/result-set-test.js.es6 | 68 ++++---- test/javascripts/models/store-test.js.es6 | 161 ++++++++---------- .../javascripts/models/user-badge-test.js.es6 | 25 ++- 10 files changed, 241 insertions(+), 318 deletions(-) diff --git a/test/javascripts/controllers/history-test.js.es6 b/test/javascripts/controllers/history-test.js.es6 index 0aeccda048..6d8ccae7cf 100644 --- a/test/javascripts/controllers/history-test.js.es6 +++ b/test/javascripts/controllers/history-test.js.es6 @@ -1,6 +1,6 @@ moduleFor("controller:history"); -QUnit.test("displayEdit", function(assert) { +QUnit.test("displayEdit", async function(assert) { const HistoryController = this.subject(); HistoryController.setProperties({ @@ -82,8 +82,8 @@ QUnit.test("displayEdit", function(assert) { } }); - HistoryController.bodyDiffChanged().then(() => { - const output = HistoryController.get("bodyDiff"); - assert.equal(output, expectedOutput, "it keeps safe HTML"); - }); + await HistoryController.bodyDiffChanged(); + + const output = HistoryController.get("bodyDiff"); + assert.equal(output, expectedOutput, "it keeps safe HTML"); }); diff --git a/test/javascripts/helpers/qunit-helpers.js.es6 b/test/javascripts/helpers/qunit-helpers.js.es6 index 34d92149b7..4b6ed9330f 100644 --- a/test/javascripts/helpers/qunit-helpers.js.es6 +++ b/test/javascripts/helpers/qunit-helpers.js.es6 @@ -1,5 +1,4 @@ import { isEmpty } from "@ember/utils"; -import { run } from "@ember/runloop"; import { later } from "@ember/runloop"; /* global QUnit, resetSite */ @@ -156,16 +155,6 @@ export function controllerFor(controller, model) { return controller; } -export function asyncTestDiscourse(text, func) { - QUnit.test(text, function(assert) { - const done = assert.async(); - run(() => { - func.call(this, assert); - done(); - }); - }); -} - export function fixture(selector) { if (selector) { return $("#qunit-fixture").find(selector); diff --git a/test/javascripts/lib/load-script-test.js.es6 b/test/javascripts/lib/load-script-test.js.es6 index 1d3094bdf7..e73a1bafa9 100644 --- a/test/javascripts/lib/load-script-test.js.es6 +++ b/test/javascripts/lib/load-script-test.js.es6 @@ -12,11 +12,10 @@ QUnit.skip( const src = "/javascripts/ace/ace.js"; - await loadScript(src).then(() => { - assert.ok( - typeof window.ace !== "undefined", - "callbacks should only be executed after the script has fully loaded" - ); - }); + await loadScript(src); + assert.ok( + typeof window.ace !== "undefined", + "callbacks should only be executed after the script has fully loaded" + ); } ); diff --git a/test/javascripts/lib/preload-store-test.js.es6 b/test/javascripts/lib/preload-store-test.js.es6 index b0560b169c..e25e89ee82 100644 --- a/test/javascripts/lib/preload-store-test.js.es6 +++ b/test/javascripts/lib/preload-store-test.js.es6 @@ -1,5 +1,4 @@ import PreloadStore from "preload-store"; -import { asyncTestDiscourse } from "helpers/qunit-helpers"; import { Promise } from "rsvp"; QUnit.module("preload-store", { @@ -22,81 +21,45 @@ QUnit.test("remove", assert => { assert.blank(PreloadStore.get("bane"), "removes the value if the key exists"); }); -asyncTestDiscourse( +QUnit.test( "getAndRemove returns a promise that resolves to null", - function(assert) { - assert.expect(1); - - const done = assert.async(); - PreloadStore.getAndRemove("joker").then(function(result) { - assert.blank(result); - done(); - }); + async assert => { + assert.blank(await PreloadStore.getAndRemove("joker")); } ); -asyncTestDiscourse( +QUnit.test( "getAndRemove returns a promise that resolves to the result of the finder", - function(assert) { - assert.expect(1); + async assert => { + const finder = () => "batdance"; + const result = await PreloadStore.getAndRemove("joker", finder); - const done = assert.async(); - const finder = function() { - return "batdance"; - }; - PreloadStore.getAndRemove("joker", finder).then(function(result) { - assert.equal(result, "batdance"); - done(); - }); + assert.equal(result, "batdance"); } ); -asyncTestDiscourse( +QUnit.test( "getAndRemove returns a promise that resolves to the result of the finder's promise", - function(assert) { - assert.expect(1); + async assert => { + const finder = () => Promise.resolve("hahahah"); + const result = await PreloadStore.getAndRemove("joker", finder); - const finder = function() { - return new Promise(function(resolve) { - resolve("hahahah"); - }); - }; - - const done = assert.async(); - PreloadStore.getAndRemove("joker", finder).then(function(result) { - assert.equal(result, "hahahah"); - done(); - }); + assert.equal(result, "hahahah"); } ); -asyncTestDiscourse( +QUnit.test( "returns a promise that rejects with the result of the finder's rejected promise", - function(assert) { - assert.expect(1); + async assert => { + const finder = () => Promise.reject("error"); - const finder = function() { - return new Promise(function(resolve, reject) { - reject("error"); - }); - }; - - const done = assert.async(); - PreloadStore.getAndRemove("joker", finder).then(null, function(result) { + await PreloadStore.getAndRemove("joker", finder).catch(result => { assert.equal(result, "error"); - done(); }); } ); -asyncTestDiscourse("returns a promise that resolves to 'evil'", function( - assert -) { - assert.expect(1); - - const done = assert.async(); - PreloadStore.getAndRemove("bane").then(function(result) { - assert.equal(result, "evil"); - done(); - }); +QUnit.test("returns a promise that resolves to 'evil'", async assert => { + const result = await PreloadStore.getAndRemove("bane"); + assert.equal(result, "evil"); }); diff --git a/test/javascripts/models/post-stream-test.js.es6 b/test/javascripts/models/post-stream-test.js.es6 index 9ba4632041..f7a587333f 100644 --- a/test/javascripts/models/post-stream-test.js.es6 +++ b/test/javascripts/models/post-stream-test.js.es6 @@ -446,7 +446,7 @@ QUnit.test("storePost", assert => { assert.equal(stored, postWithoutId, "it returns the same post back"); }); -QUnit.test("identity map", assert => { +QUnit.test("identity map", async assert => { const postStream = buildStream(1234); const store = postStream.store; @@ -465,34 +465,29 @@ QUnit.test("identity map", assert => { assert.blank(postStream.findLoadedPost(4), "it can't find uncached posts"); // Find posts by ids uses the identity map - return postStream.findPostsByIds([1, 2, 3]).then(result => { - assert.equal(result.length, 3); - assert.equal(result.objectAt(0), p1); - assert.equal(result.objectAt(1).get("post_number"), 2); - assert.equal(result.objectAt(2), p3); - }); + const result = await postStream.findPostsByIds([1, 2, 3]); + assert.equal(result.length, 3); + assert.equal(result.objectAt(0), p1); + assert.equal(result.objectAt(1).get("post_number"), 2); + assert.equal(result.objectAt(2), p3); }); -QUnit.test("loadIntoIdentityMap with no data", assert => { - return buildStream(1234) - .loadIntoIdentityMap([]) - .then(result => { - assert.equal(result.length, 0, "requesting no posts produces no posts"); - }); +QUnit.test("loadIntoIdentityMap with no data", async assert => { + const result = await buildStream(1234).loadIntoIdentityMap([]); + assert.equal(result.length, 0, "requesting no posts produces no posts"); }); -QUnit.test("loadIntoIdentityMap with post ids", assert => { +QUnit.test("loadIntoIdentityMap with post ids", async assert => { const postStream = buildStream(1234); + await postStream.loadIntoIdentityMap([10]); - return postStream.loadIntoIdentityMap([10]).then(function() { - assert.present( - postStream.findLoadedPost(10), - "it adds the returned post to the store" - ); - }); + assert.present( + postStream.findLoadedPost(10), + "it adds the returned post to the store" + ); }); -QUnit.test("appendMore for megatopic", assert => { +QUnit.test("appendMore for megatopic", async assert => { const postStream = buildStream(1234); const store = createStore(); const post = store.createRecord("post", { id: 1, post_number: 1 }); @@ -502,21 +497,20 @@ QUnit.test("appendMore for megatopic", assert => { posts: [post] }); - return postStream.appendMore().then(() => { - assert.present( - postStream.findLoadedPost(2), - "it adds the returned post to the store" - ); + await postStream.appendMore(); + assert.present( + postStream.findLoadedPost(2), + "it adds the returned post to the store" + ); - assert.equal( - postStream.get("posts").length, - 6, - "it adds the right posts into the stream" - ); - }); + assert.equal( + postStream.get("posts").length, + 6, + "it adds the right posts into the stream" + ); }); -QUnit.test("prependMore for megatopic", assert => { +QUnit.test("prependMore for megatopic", async assert => { const postStream = buildStream(1234); const store = createStore(); const post = store.createRecord("post", { id: 6, post_number: 6 }); @@ -526,18 +520,17 @@ QUnit.test("prependMore for megatopic", assert => { posts: [post] }); - return postStream.prependMore().then(() => { - assert.present( - postStream.findLoadedPost(5), - "it adds the returned post to the store" - ); + await postStream.prependMore(); + assert.present( + postStream.findLoadedPost(5), + "it adds the returned post to the store" + ); - assert.equal( - postStream.get("posts").length, - 6, - "it adds the right posts into the stream" - ); - }); + assert.equal( + postStream.get("posts").length, + 6, + "it adds the right posts into the stream" + ); }); QUnit.test("staging and undoing a new post", assert => { @@ -865,7 +858,7 @@ QUnit.test("triggerNewPostInStream for ignored posts", async assert => { ); }); -QUnit.test("postsWithPlaceholders", assert => { +QUnit.test("postsWithPlaceholders", async assert => { const postStream = buildStream(4964, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); const postsWithPlaceholders = postStream.get("postsWithPlaceholders"); const store = postStream.store; @@ -903,16 +896,15 @@ QUnit.test("postsWithPlaceholders", assert => { assert.ok(postsWithPlaceholders.objectAt(3) !== p4); assert.ok(testProxy.objectAt(3) !== p4); - return promise.then(() => { - assert.equal(postsWithPlaceholders.objectAt(3), p4); - assert.equal( - postsWithPlaceholders.get("length"), - 8, - "have a larger placeholder window when loaded" - ); - assert.equal(testProxy.get("length"), 8); - assert.equal(testProxy.objectAt(3), p4); - }); + await promise; + assert.equal(postsWithPlaceholders.objectAt(3), p4); + assert.equal( + postsWithPlaceholders.get("length"), + 8, + "have a larger placeholder window when loaded" + ); + assert.equal(testProxy.get("length"), 8); + assert.equal(testProxy.objectAt(3), p4); }); QUnit.test("filteredPostsCount", assert => { diff --git a/test/javascripts/models/post-test.js.es6 b/test/javascripts/models/post-test.js.es6 index a96c32bb91..ad7fc393ec 100644 --- a/test/javascripts/models/post-test.js.es6 +++ b/test/javascripts/models/post-test.js.es6 @@ -80,20 +80,20 @@ QUnit.test("destroy by staff", assert => { ); }); -QUnit.test("destroy by non-staff", assert => { - var originalCooked = "this is the original cooked value", - user = User.create({ username: "evil trout" }), - post = buildPost({ user: user, cooked: originalCooked }); +QUnit.test("destroy by non-staff", async assert => { + const originalCooked = "this is the original cooked value"; + const user = User.create({ username: "evil trout" }); + const post = buildPost({ user: user, cooked: originalCooked }); - return post.destroy(user).then(() => { - assert.ok( - !post.get("can_delete"), - "the post can't be deleted again in this session" - ); - assert.ok( - post.get("cooked") !== originalCooked, - "the cooked content changed" - ); - assert.equal(post.get("version"), 2, "the version number increased"); - }); + await post.destroy(user); + + assert.ok( + !post.get("can_delete"), + "the post can't be deleted again in this session" + ); + assert.ok( + post.get("cooked") !== originalCooked, + "the cooked content changed" + ); + assert.equal(post.get("version"), 2, "the version number increased"); }); diff --git a/test/javascripts/models/rest-model-test.js.es6 b/test/javascripts/models/rest-model-test.js.es6 index c5e66c4867..c7c44bba26 100644 --- a/test/javascripts/models/rest-model-test.js.es6 +++ b/test/javascripts/models/rest-model-test.js.es6 @@ -18,43 +18,42 @@ QUnit.test("munging", assert => { assert.equal(g.get("inverse"), 0.6, "it runs `munge` on `create`"); }); -QUnit.test("update", assert => { +QUnit.test("update", async assert => { const store = createStore(); - return store.find("widget", 123).then(function(widget) { - assert.equal(widget.get("name"), "Trout Lure"); - assert.ok(!widget.get("isSaving"), "it is not saving"); + const widget = await store.find("widget", 123); + assert.equal(widget.get("name"), "Trout Lure"); + assert.ok(!widget.get("isSaving"), "it is not saving"); - const promise = widget.update({ name: "new name" }); - assert.ok(widget.get("isSaving"), "it is saving"); + const promise = widget.update({ name: "new name" }); + assert.ok(widget.get("isSaving"), "it is saving"); - promise.then(function(result) { - assert.ok(!widget.get("isSaving"), "it is no longer saving"); - assert.equal(widget.get("name"), "new name"); + const result = await promise; + assert.ok(!widget.get("isSaving"), "it is no longer saving"); + assert.equal(widget.get("name"), "new name"); - assert.ok(result.target, "it has a reference to the record"); - assert.equal(result.target.name, widget.get("name")); - }); - }); + assert.ok(result.target, "it has a reference to the record"); + assert.equal(result.target.name, widget.get("name")); }); -QUnit.test("updating simultaneously", assert => { +QUnit.test("updating simultaneously", async assert => { assert.expect(2); const store = createStore(); - return store.find("widget", 123).then(function(widget) { - const firstPromise = widget.update({ name: "new name" }); - const secondPromise = widget.update({ name: "new name" }); - firstPromise.then(function() { - assert.ok(true, "the first promise succeeeds"); - }); + const widget = await store.find("widget", 123); - secondPromise.catch(function() { - assert.ok(true, "the second promise fails"); - }); + const firstPromise = widget.update({ name: "new name" }); + const secondPromise = widget.update({ name: "new name" }); + + firstPromise.then(function() { + assert.ok(true, "the first promise succeeeds"); + }); + + secondPromise.catch(function() { + assert.ok(true, "the second promise fails"); }); }); -QUnit.test("save new", assert => { +QUnit.test("save new", async assert => { const store = createStore(); const widget = store.createRecord("widget"); @@ -65,16 +64,15 @@ QUnit.test("save new", assert => { const promise = widget.save({ name: "Evil Widget" }); assert.ok(widget.get("isSaving"), "it is not saving"); - return promise.then(function(result) { - assert.ok(!widget.get("isSaving"), "it is no longer saving"); - assert.ok(widget.get("id"), "it has an id"); - assert.ok(widget.get("name"), "Evil Widget"); - assert.ok(widget.get("isCreated"), "it is created"); - assert.ok(!widget.get("isNew"), "it is no longer new"); + const result = await promise; + assert.ok(!widget.get("isSaving"), "it is no longer saving"); + assert.ok(widget.get("id"), "it has an id"); + assert.ok(widget.get("name"), "Evil Widget"); + assert.ok(widget.get("isCreated"), "it is created"); + assert.ok(!widget.get("isNew"), "it is no longer new"); - assert.ok(result.target, "it has a reference to the record"); - assert.equal(result.target.name, widget.get("name")); - }); + assert.ok(result.target, "it has a reference to the record"); + assert.equal(result.target.name, widget.get("name")); }); QUnit.test("creating simultaneously", assert => { diff --git a/test/javascripts/models/result-set-test.js.es6 b/test/javascripts/models/result-set-test.js.es6 index 1f819b317e..f80ae1901c 100644 --- a/test/javascripts/models/result-set-test.js.es6 +++ b/test/javascripts/models/result-set-test.js.es6 @@ -4,50 +4,46 @@ import ResultSet from "discourse/models/result-set"; import createStore from "helpers/create-store"; QUnit.test("defaults", assert => { - const rs = ResultSet.create({ content: [] }); - assert.equal(rs.get("length"), 0); - assert.equal(rs.get("totalRows"), 0); - assert.ok(!rs.get("loadMoreUrl")); - assert.ok(!rs.get("loading")); - assert.ok(!rs.get("loadingMore")); - assert.ok(!rs.get("refreshing")); + const resultSet = ResultSet.create({ content: [] }); + assert.equal(resultSet.get("length"), 0); + assert.equal(resultSet.get("totalRows"), 0); + assert.ok(!resultSet.get("loadMoreUrl")); + assert.ok(!resultSet.get("loading")); + assert.ok(!resultSet.get("loadingMore")); + assert.ok(!resultSet.get("refreshing")); }); -QUnit.test("pagination support", assert => { +QUnit.test("pagination support", async assert => { const store = createStore(); - return store.findAll("widget").then(function(rs) { - assert.equal(rs.get("length"), 2); - assert.equal(rs.get("totalRows"), 4); - assert.ok(rs.get("loadMoreUrl"), "has a url to load more"); - assert.ok(!rs.get("loadingMore"), "it is not loading more"); - assert.ok(rs.get("canLoadMore")); + const resultSet = await store.findAll("widget"); + assert.equal(resultSet.get("length"), 2); + assert.equal(resultSet.get("totalRows"), 4); + assert.ok(resultSet.get("loadMoreUrl"), "has a url to load more"); + assert.ok(!resultSet.get("loadingMore"), "it is not loading more"); + assert.ok(resultSet.get("canLoadMore")); - const promise = rs.loadMore(); + const promise = resultSet.loadMore(); + assert.ok(resultSet.get("loadingMore"), "it is loading more"); - assert.ok(rs.get("loadingMore"), "it is loading more"); - promise.then(function() { - assert.ok(!rs.get("loadingMore"), "it finished loading more"); - assert.equal(rs.get("length"), 4); - assert.ok(!rs.get("loadMoreUrl")); - assert.ok(!rs.get("canLoadMore")); - }); - }); + await promise; + assert.ok(!resultSet.get("loadingMore"), "it finished loading more"); + assert.equal(resultSet.get("length"), 4); + assert.ok(!resultSet.get("loadMoreUrl")); + assert.ok(!resultSet.get("canLoadMore")); }); -QUnit.test("refresh support", assert => { +QUnit.test("refresh support", async assert => { const store = createStore(); - return store.findAll("widget").then(function(rs) { - assert.equal( - rs.get("refreshUrl"), - "/widgets?refresh=true", - "it has the refresh url" - ); + const resultSet = await store.findAll("widget"); + assert.equal( + resultSet.get("refreshUrl"), + "/widgets?refresh=true", + "it has the refresh url" + ); - const promise = rs.refresh(); + const promise = resultSet.refresh(); + assert.ok(resultSet.get("refreshing"), "it is refreshing"); - assert.ok(rs.get("refreshing"), "it is refreshing"); - promise.then(function() { - assert.ok(!rs.get("refreshing"), "it is finished refreshing"); - }); - }); + await promise; + assert.ok(!resultSet.get("refreshing"), "it is finished refreshing"); }); diff --git a/test/javascripts/models/store-test.js.es6 b/test/javascripts/models/store-test.js.es6 index f8d9ba1c03..2e220b152c 100644 --- a/test/javascripts/models/store-test.js.es6 +++ b/test/javascripts/models/store-test.js.es6 @@ -50,77 +50,68 @@ QUnit.test( } ); -QUnit.test("find", assert => { +QUnit.test("find", async assert => { const store = createStore(); - return store.find("widget", 123).then(function(w) { - assert.equal(w.get("name"), "Trout Lure"); - assert.equal(w.get("id"), 123); - assert.ok(!w.get("isNew"), "found records are not new"); - assert.equal(w.get("extras.hello"), "world", "extra attributes are set"); + const widget = await store.find("widget", 123); + assert.equal(widget.get("name"), "Trout Lure"); + assert.equal(widget.get("id"), 123); + assert.ok(!widget.get("isNew"), "found records are not new"); + assert.equal(widget.get("extras.hello"), "world", "extra attributes are set"); - // A second find by id returns the same object - store.find("widget", 123).then(function(w2) { - assert.equal(w, w2); - assert.equal(w.get("extras.hello"), "world", "extra attributes are set"); - }); - }); + // A second find by id returns the same object + const widget2 = await store.find("widget", 123); + assert.equal(widget, widget2); + assert.equal(widget.get("extras.hello"), "world", "extra attributes are set"); }); -QUnit.test("find with object id", assert => { +QUnit.test("find with object id", async assert => { const store = createStore(); - return store.find("widget", { id: 123 }).then(function(w) { - assert.equal(w.get("firstObject.name"), "Trout Lure"); - }); + const widget = await store.find("widget", { id: 123 }); + assert.equal(widget.get("firstObject.name"), "Trout Lure"); }); -QUnit.test("find with query param", assert => { +QUnit.test("find with query param", async assert => { const store = createStore(); - return store.find("widget", { name: "Trout Lure" }).then(function(w) { - assert.equal(w.get("firstObject.id"), 123); - }); + const widget = await store.find("widget", { name: "Trout Lure" }); + assert.equal(widget.get("firstObject.id"), 123); }); -QUnit.test("findStale with no stale results", assert => { +QUnit.test("findStale with no stale results", async assert => { const store = createStore(); const stale = store.findStale("widget", { name: "Trout Lure" }); assert.ok(!stale.hasResults, "there are no stale results"); assert.ok(!stale.results, "results are present"); - return stale.refresh().then(function(w) { - assert.equal( - w.get("firstObject.id"), - 123, - "a `refresh()` method provides results for stale" - ); - }); + const widget = await stale.refresh(); + assert.equal( + widget.get("firstObject.id"), + 123, + "a `refresh()` method provides results for stale" + ); }); -QUnit.test("update", assert => { +QUnit.test("update", async assert => { const store = createStore(); - return store.update("widget", 123, { name: "hello" }).then(function(result) { - assert.ok(result); - }); + const result = await store.update("widget", 123, { name: "hello" }); + assert.ok(result); }); -QUnit.test("update with a multi world name", function(assert) { +QUnit.test("update with a multi world name", async assert => { const store = createStore(); - return store - .update("cool-thing", 123, { name: "hello" }) - .then(function(result) { - assert.ok(result); - assert.equal(result.payload.name, "hello"); - }); + const result = await store.update("cool-thing", 123, { name: "hello" }); + assert.ok(result); + assert.equal(result.payload.name, "hello"); }); -QUnit.test("findAll", assert => { +QUnit.test("findAll", async assert => { const store = createStore(); - return store.findAll("widget").then(function(result) { - assert.equal(result.get("length"), 2); - const w = result.findBy("id", 124); - assert.ok(!w.get("isNew"), "found records are not new"); - assert.equal(w.get("name"), "Evil Repellant"); - }); + const result = await store.findAll("widget"); + assert.equal(result.get("length"), 2); + + const widget = result.findBy("id", 124); + assert.ok(!widget.get("isNew"), "found records are not new"); + assert.equal(widget.get("name"), "Evil Repellant"); }); QUnit.test("destroyRecord", function(assert) { @@ -140,59 +131,57 @@ QUnit.test("destroyRecord when new", function(assert) { }); }); -QUnit.test("find embedded", function(assert) { +QUnit.test("find embedded", async assert => { const store = createStore(); - return store.find("fruit", 1).then(function(f) { - assert.ok(f.get("farmer"), "it has the embedded object"); + const fruit = await store.find("fruit", 1); + assert.ok(fruit.get("farmer"), "it has the embedded object"); - const fruitCols = f.get("colors"); - assert.equal(fruitCols.length, 2); - assert.equal(fruitCols[0].get("id"), 1); - assert.equal(fruitCols[1].get("id"), 2); + const fruitCols = fruit.get("colors"); + assert.equal(fruitCols.length, 2); + assert.equal(fruitCols[0].get("id"), 1); + assert.equal(fruitCols[1].get("id"), 2); - assert.ok(f.get("category"), "categories are found automatically"); - }); + assert.ok(fruit.get("category"), "categories are found automatically"); }); QUnit.test("embedded records can be cleared", async assert => { const store = createStore(); - let f = await store.find("fruit", 4); - f.set("farmer", { dummy: "object" }); - f = await store.find("fruit", 4); - assert.ok(!f.get("farmer")); + let fruit = await store.find("fruit", 4); + fruit.set("farmer", { dummy: "object" }); + + fruit = await store.find("fruit", 4); + assert.ok(!fruit.get("farmer")); }); -QUnit.test("meta types", function(assert) { +QUnit.test("meta types", async assert => { const store = createStore(); - return store.find("barn", 1).then(function(f) { - assert.equal( - f.get("owner.name"), - "Old MacDonald", - "it has the embedded farmer" - ); - }); + const barn = await store.find("barn", 1); + assert.equal( + barn.get("owner.name"), + "Old MacDonald", + "it has the embedded farmer" + ); }); -QUnit.test("findAll embedded", function(assert) { +QUnit.test("findAll embedded", async assert => { const store = createStore(); - return store.findAll("fruit").then(function(fruits) { - assert.equal(fruits.objectAt(0).get("farmer.name"), "Old MacDonald"); - assert.equal( - fruits.objectAt(0).get("farmer"), - fruits.objectAt(1).get("farmer"), - "points at the same object" - ); - assert.equal( - fruits.get("extras.hello"), - "world", - "it can supply extra information" - ); + const fruits = await store.findAll("fruit"); + assert.equal(fruits.objectAt(0).get("farmer.name"), "Old MacDonald"); + assert.equal( + fruits.objectAt(0).get("farmer"), + fruits.objectAt(1).get("farmer"), + "points at the same object" + ); + assert.equal( + fruits.get("extras.hello"), + "world", + "it can supply extra information" + ); - const fruitCols = fruits.objectAt(0).get("colors"); - assert.equal(fruitCols.length, 2); - assert.equal(fruitCols[0].get("id"), 1); - assert.equal(fruitCols[1].get("id"), 2); + const fruitCols = fruits.objectAt(0).get("colors"); + assert.equal(fruitCols.length, 2); + assert.equal(fruitCols[0].get("id"), 1); + assert.equal(fruitCols[1].get("id"), 2); - assert.equal(fruits.objectAt(2).get("farmer.name"), "Luke Skywalker"); - }); + assert.equal(fruits.objectAt(2).get("farmer.name"), "Luke Skywalker"); }); diff --git a/test/javascripts/models/user-badge-test.js.es6 b/test/javascripts/models/user-badge-test.js.es6 index 2a0fdd9d6f..80d2432453 100644 --- a/test/javascripts/models/user-badge-test.js.es6 +++ b/test/javascripts/models/user-badge-test.js.es6 @@ -35,26 +35,23 @@ QUnit.test("createFromJson array", assert => { ); }); -QUnit.test("findByUsername", assert => { - return UserBadge.findByUsername("anne3").then(function(badges) { - assert.ok(Array.isArray(badges), "returns an array"); - }); +QUnit.test("findByUsername", async assert => { + const badges = await UserBadge.findByUsername("anne3"); + assert.ok(Array.isArray(badges), "returns an array"); }); -QUnit.test("findByBadgeId", assert => { - return UserBadge.findByBadgeId(880).then(function(badges) { - assert.ok(Array.isArray(badges), "returns an array"); - }); +QUnit.test("findByBadgeId", async assert => { + const badges = await UserBadge.findByBadgeId(880); + assert.ok(Array.isArray(badges), "returns an array"); }); -QUnit.test("grant", assert => { - return UserBadge.grant(1, "username").then(function(userBadge) { - assert.ok(!Array.isArray(userBadge), "does not return an array"); - }); +QUnit.test("grant", async assert => { + const userBadge = await UserBadge.grant(1, "username"); + assert.ok(!Array.isArray(userBadge), "does not return an array"); }); -QUnit.test("revoke", assert => { +QUnit.test("revoke", async assert => { assert.expect(0); const userBadge = UserBadge.create({ id: 1 }); - return userBadge.revoke(); + await userBadge.revoke(); }); From ee35bbdbba020de6fb27369e2bbfe4f5ae95c847 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 16:34:53 -0500 Subject: [PATCH 0059/1830] Build(deps): Bump oj from 3.10.2 to 3.10.3 (#9092) Bumps [oj](https://github.com/ohler55/oj) from 3.10.2 to 3.10.3. - [Release notes](https://github.com/ohler55/oj/releases) - [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ohler55/oj/compare/v3.10.2...v3.10.3) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 8eaa96fb40..f6dafec9a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -215,7 +215,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.10.2) + oj (3.10.3) omniauth (1.9.0) hashie (>= 3.4.6, < 3.7.0) rack (>= 1.6.2, < 3) From 8a696a4ffc2fcedfcd9a7b4883d7553d6fada4c9 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2020 16:35:13 -0500 Subject: [PATCH 0060/1830] Build(deps-dev): Bump annotate from 3.0.3 to 3.1.0 (#9091) Bumps [annotate](https://github.com/ctran/annotate_models) from 3.0.3 to 3.1.0. - [Release notes](https://github.com/ctran/annotate_models/releases) - [Changelog](https://github.com/ctran/annotate_models/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ctran/annotate_models/compare/v3.0.3...v3.1.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index f6dafec9a5..1134290d72 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,7 +40,7 @@ GEM zeitwerk (~> 2.2) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - annotate (3.0.3) + annotate (3.1.0) activerecord (>= 3.2, < 7.0) rake (>= 10.4, < 14.0) ast (2.4.0) From 0388653a4d7d422a1525649a155182446da34405 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Tue, 3 Mar 2020 10:03:58 +1100 Subject: [PATCH 0061/1830] DEV: Upload and secure media retroactive rake task improvements (#9027) * Add uploads:sync_s3_acls rake task to ensure the ACLs in S3 are the correct (public-read or private) setting based on upload security * Improved uploads:disable_secure_media to be more efficient and provide better messages to the user. * Rename uploads:ensure_correct_acl task to uploads:secure_upload_analyse_and_update as it does more than check the ACL * Many improvements to uploads:secure_upload_analyse_and_update * Make sure that upload.access_control_post is unscoped so deleted posts are still fetched, because they still affect the security of the upload. * Add escape hatch for capture_stdout in the form of RAILS_ENABLE_TEST_STDOUT. If provided the capture_stdout code will be ignored, so you can see the output if you need. --- app/models/upload.rb | 6 + lib/tasks/uploads.rake | 195 +++++++++++++----- lib/upload_security.rb | 3 - .../update_private_uploads_acl_spec.rb | 20 +- spec/lib/upload_security_spec.rb | 11 +- spec/support/helpers.rb | 4 + spec/tasks/uploads_spec.rb | 94 ++++++++- 7 files changed, 271 insertions(+), 62 deletions(-) diff --git a/app/models/upload.rb b/app/models/upload.rb index d306ef9538..fe6f5c3e0e 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -14,6 +14,12 @@ class Upload < ActiveRecord::Base belongs_to :user belongs_to :access_control_post, class_name: 'Post' + # when we access this post we don't care if the post + # is deleted + def access_control_post + Post.unscoped { super } + end + has_many :post_uploads, dependent: :destroy has_many :posts, through: :post_uploads diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index 7480cb73c4..33c69b7d6c 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -615,6 +615,21 @@ task "uploads:recover" => :environment do end end +task "uploads:sync_s3_acls" => :environment do + RailsMultisite::ConnectionManagement.each_connection do |db| + unless Discourse.store.external? + puts "This task only works for external storage." + exit 1 + end + + puts "CAUTION: This task may take a long time to complete!" + puts "-" * 30 + puts "Uploads marked as secure will get a private ACL, and uploads marked as not secure will get a public ACL." + adjust_acls(Upload.find_each(batch_size: 100)) + puts "", "Upload ACL sync complete!" + end +end + task "uploads:disable_secure_media" => :environment do RailsMultisite::ConnectionManagement.each_connection do |db| unless Discourse.store.external? @@ -628,43 +643,56 @@ task "uploads:disable_secure_media" => :environment do secure_uploads = Upload.includes(:posts).where(secure: true) secure_upload_count = secure_uploads.count + uploads_to_adjust_acl_for = [] + posts_to_rebake = {} i = 0 secure_uploads.find_each(batch_size: 20).each do |upload| - Upload.transaction do - upload.secure = false + uploads_to_adjust_acl_for << upload - RakeHelpers.print_status_with_label("Updating ACL for upload #{upload.id}.......", i, secure_upload_count) - Discourse.store.update_upload_ACL(upload) - - RakeHelpers.print_status_with_label("Rebaking posts for upload #{upload.id}.......", i, secure_upload_count) - upload.posts.each(&:rebake!) - upload.save - - i += 1 + upload.posts.each do |post| + # don't want unnecessary double-ups + next if posts_to_rebake.key?(post.id) + posts_to_rebake[post.id] = post end + + i += 1 end + puts "", "Marking #{secure_upload_count} uploads as not secure.", "" + secure_uploads.update_all(secure: false) + + adjust_acls(uploads_to_adjust_acl_for) + post_rebake_errors = rebake_upload_posts(posts_to_rebake) + log_rebake_errors(post_rebake_errors) + RakeHelpers.print_status_with_label("Rebaking and updating complete! ", i, secure_upload_count) - puts "" end - puts "Secure media is now disabled!", "" + puts "", "Secure media is now disabled!", "" +end + +# Renamed to uploads:secure_upload_analyse_and_update +task "uploads:ensure_correct_acl" => :environment do + puts "This task has been deprecated, run uploads:secure_upload_analyse_and_update task instead." + exit 1 end ## # Run this task whenever the secure_media or login_required # settings are changed for a Discourse instance to update -# the upload secure flag and S3 upload ACLs. -task "uploads:ensure_correct_acl" => :environment do +# the upload secure flag and S3 upload ACLs. Any uploads that +# have their secure status changed will have all associated posts +# rebaked. +task "uploads:secure_upload_analyse_and_update" => :environment do RailsMultisite::ConnectionManagement.each_connection do |db| unless Discourse.store.external? puts "This task only works for external storage." exit 1 end - puts "Ensuring correct ACL for uploads in #{db}...", "" - + puts "Analyzing security for uploads in #{db}...", "" + upload_ids_to_mark_as_secure, upload_ids_to_mark_as_not_secure, posts_to_rebake, uploads_to_adjust_acl_for = nil Upload.transaction do mark_secure_in_loop_because_no_login_required = false @@ -677,19 +705,23 @@ task "uploads:ensure_correct_acl" => :environment do update_uploads_access_control_post end - # First of all only get relevant uploads (supported media). - # - # Also only get uploads that are not for a theme or a site setting, so only - # get post related uploads. - uploads_with_supported_media = Upload.includes(:posts, :access_control_post, :optimized_images).where( - "LOWER(original_filename) SIMILAR TO '%\.(jpg|jpeg|png|gif|svg|ico|mp3|ogg|wav|m4a|mov|mp4|webm|ogv)'" - ).joins(:post_uploads) + # Get all uploads in the database, including optimized images. Both media (images, videos, + # etc) along with attachments (pdfs, txt, etc.) must be loaded because all can be marked as + # secure based on site settings. + uploads_to_update = Upload.includes(:posts, :optimized_images).joins(:post_uploads) - puts "There are #{uploads_with_supported_media.count} upload(s) with supported media that could be marked secure.", "" + # we do this to avoid a heavier post query, and to make sure we only + # get unique posts AND include deleted posts (unscoped) + unique_access_control_posts = Post.unscoped.select(:id, :topic_id).includes(topic: :category).where(id: uploads_to_update.pluck(:access_control_post_id).uniq) + uploads_to_update.each do |upload| + upload.access_control_post = unique_access_control_posts.find { |post| post.id == upload.access_control_post_id } + end + + puts "There are #{uploads_to_update.count} upload(s) that could be marked secure.", "" # Simply mark all these uploads as secure if login_required because no anons will be able to access them if SiteSetting.login_required? - mark_all_as_secure_login_required(uploads_with_supported_media) + mark_secure_in_loop_because_no_login_required = false else # If NOT login_required, then we have to go for the other slower flow, where in the loop @@ -698,24 +730,50 @@ task "uploads:ensure_correct_acl" => :environment do puts "Marking posts as secure in the next step because login_required is false." end - puts "", "Determining which of #{uploads_with_supported_media.count} upload posts need to be marked secure and be rebaked.", "" + puts "", "Analysing which of #{uploads_to_update.count} uploads need to be marked secure and be rebaked.", "" - upload_ids_to_mark_as_secure, posts_to_rebake = determine_upload_security_and_posts_to_rebake( - uploads_with_supported_media, mark_secure_in_loop_because_no_login_required + upload_ids_to_mark_as_secure, + upload_ids_to_mark_as_not_secure, + posts_to_rebake, + uploads_to_adjust_acl_for = determine_upload_security_and_posts_to_rebake( + uploads_to_update, mark_secure_in_loop_because_no_login_required ) - mark_specific_uploads_as_secure_no_login_required(upload_ids_to_mark_as_secure) - - post_rebake_errors = rebake_upload_posts(posts_to_rebake) - log_rebake_errors(post_rebake_errors) + if !SiteSetting.login_required? + update_specific_upload_security_no_login_required(upload_ids_to_mark_as_secure, upload_ids_to_mark_as_not_secure) + else + mark_all_as_secure_login_required(uploads_to_update) + end end + + # Enqueue rebakes AFTER upload transaction complete, so there is no race condition + # between updating the DB and the rebakes occurring. + post_rebake_errors = rebake_upload_posts(posts_to_rebake) + log_rebake_errors(post_rebake_errors) + + # Also do this AFTER upload transaction complete so we don't end up with any + # errors leaving ACLs in a bad state (the ACL sync task can be run to fix any + # outliers at any time). + adjust_acls(uploads_to_adjust_acl_for) end - puts "", "Done" + puts "", "", "Done!" end -def mark_all_as_secure_login_required(uploads_with_supported_media) - puts "Marking #{uploads_with_supported_media.count} upload(s) as secure because login_required is true.", "" - uploads_with_supported_media.update_all(secure: true) +def adjust_acls(uploads_to_adjust_acl_for) + total_count = uploads_to_adjust_acl_for.respond_to?(:length) ? uploads_to_adjust_acl_for.length : uploads_to_adjust_acl_for.count + puts "", "Updating ACL for #{total_count} uploads.", "" + i = 0 + uploads_to_adjust_acl_for.each do |upload| + RakeHelpers.print_status_with_label("Updating ACL for upload.......", i, total_count) + Discourse.store.update_upload_ACL(upload) + i += 1 + end + RakeHelpers.print_status_with_label("Updaing ACLs complete! ", i, total_count) +end + +def mark_all_as_secure_login_required(uploads_to_update) + puts "Marking #{uploads_to_update.count} upload(s) as secure because login_required is true.", "" + uploads_to_update.update_all(secure: true) puts "Finished marking upload(s) as secure." end @@ -727,11 +785,16 @@ def log_rebake_errors(rebake_errors) end end -def mark_specific_uploads_as_secure_no_login_required(upload_ids_to_mark_as_secure) - return if upload_ids_to_mark_as_secure.empty? - puts "Marking #{upload_ids_to_mark_as_secure.length} uploads as secure because UploadSecurity determined them to be secure." - Upload.where(id: upload_ids_to_mark_as_secure).update_all(secure: true) - puts "Finished marking uploads as secure." +def update_specific_upload_security_no_login_required(upload_ids_to_mark_as_secure, upload_ids_to_mark_as_not_secure) + if upload_ids_to_mark_as_secure.any? + puts "Marking #{upload_ids_to_mark_as_secure.length} uploads as secure because UploadSecurity determined them to be secure." + Upload.where(id: upload_ids_to_mark_as_secure).update_all(secure: true) + end + if upload_ids_to_mark_as_not_secure.any? + puts "Marking #{upload_ids_to_mark_as_not_secure.length} uploads as not secure because UploadSecurity determined them to be not secure." + Upload.where(id: upload_ids_to_mark_as_not_secure).update_all(secure: false) + end + puts "Finished updating upload security." end def update_uploads_access_control_post @@ -752,12 +815,13 @@ def update_uploads_access_control_post end def rebake_upload_posts(posts_to_rebake) + posts_to_rebake = posts_to_rebake.values post_rebake_errors = [] puts "", "Rebaking #{posts_to_rebake.length} posts with affected uploads.", "" begin i = 0 posts_to_rebake.each do |post| - RakeHelpers.print_status_with_label("Determining which uploads to mark secure and rebake.....", i, posts_to_rebake.length) + RakeHelpers.print_status_with_label("Rebaking posts.....", i, posts_to_rebake.length) post.rebake! i += 1 end @@ -770,32 +834,55 @@ def rebake_upload_posts(posts_to_rebake) post_rebake_errors end -def determine_upload_security_and_posts_to_rebake(uploads_with_supported_media, mark_secure_in_loop_because_no_login_required) +def determine_upload_security_and_posts_to_rebake(uploads_to_update, mark_secure_in_loop_because_no_login_required) upload_ids_to_mark_as_secure = [] - posts_to_rebake = [] + upload_ids_to_mark_as_not_secure = [] + uploads_to_adjust_acl_for = [] + posts_to_rebake = {} i = 0 - uploads_with_supported_media.find_each(batch_size: 50) do |upload_with_supported_media| - RakeHelpers.print_status_with_label("Updating ACL for upload.......", i, uploads_with_supported_media.count) + uploads_to_update.find_each(batch_size: 50) do |upload_to_update| # we just need to determine the post security here so the ACL is set to the correct thing, # because the update_upload_ACL method uses upload.secure? - upload_with_supported_media.secure = UploadSecurity.new(upload_with_supported_media).should_be_secure? - Discourse.store.update_upload_ACL(upload_with_supported_media) + original_update_secure_status = upload_to_update.secure + upload_to_update.secure = UploadSecurity.new(upload_to_update).should_be_secure? - RakeHelpers.print_status_with_label("Determining which uploads to mark secure and rebake.....", i, uploads_with_supported_media.count) - upload_with_supported_media.posts.each { |post| posts_to_rebake << post } + # no point changing ACLs or rebaking or doing any such shenanigans + # when the secure status hasn't even changed! + if original_update_secure_status == upload_to_update.secure + i += 1 + next + end - if mark_secure_in_loop_because_no_login_required && upload_with_supported_media.secure? - upload_ids_to_mark_as_secure << upload_with_supported_media.id + # we only want to update the acl later once the secure status + # has been saved in the DB; otherwise if there is a later failure + # we get stuck with an incorrect ACL in S3 + uploads_to_adjust_acl_for << upload_to_update + RakeHelpers.print_status_with_label("Analysing which upload posts to rebake.....", i, uploads_to_update.count) + upload_to_update.posts.each do |post| + # don't want unnecessary double-ups + next if posts_to_rebake.key?(post.id) + posts_to_rebake[post.id] = post + end + + # some uploads will be marked as not secure here. + # we need to address this with upload_ids_to_mark_as_not_secure + # e.g. turning off SiteSetting.login_required + if mark_secure_in_loop_because_no_login_required + if upload_to_update.secure? + upload_ids_to_mark_as_secure << upload_to_update.id + else + upload_ids_to_mark_as_not_secure << upload_to_update.id + end end i += 1 end - RakeHelpers.print_status_with_label("Determination complete! ", i, uploads_with_supported_media.count) + RakeHelpers.print_status_with_label("Analysis complete! ", i, uploads_to_update.count) puts "" - [upload_ids_to_mark_as_secure, posts_to_rebake] + [upload_ids_to_mark_as_secure, upload_ids_to_mark_as_not_secure, posts_to_rebake, uploads_to_adjust_acl_for] end def inline_uploads(post) diff --git a/lib/upload_security.rb b/lib/upload_security.rb index d2e11d9eef..2c9d2f2386 100644 --- a/lib/upload_security.rb +++ b/lib/upload_security.rb @@ -57,9 +57,6 @@ class UploadSecurity # if there is no access control post id and the upload is currently secure, we # do not want to make it un-secure to avoid unintentionally exposing it def access_control_post_has_secure_media? - # if the post is deleted the access_control_post will be blank... - # TODO: deal with this in a better way - return false if @upload.access_control_post.blank? @upload.access_control_post.with_secure_media? end diff --git a/spec/jobs/regular/update_private_uploads_acl_spec.rb b/spec/jobs/regular/update_private_uploads_acl_spec.rb index 25d6fe07d0..9c51ef734f 100644 --- a/spec/jobs/regular/update_private_uploads_acl_spec.rb +++ b/spec/jobs/regular/update_private_uploads_acl_spec.rb @@ -24,9 +24,9 @@ describe Jobs::UpdatePrivateUploadsAcl do before do SiteSetting.login_required = true SiteSetting.prevent_anons_from_downloading_files = true - SiteSetting::Upload.stubs(:enable_s3_uploads).returns(true) Discourse.stubs(:store).returns(stub(external?: false)) - SiteSetting.stubs(:secure_media?).returns(true) + enable_s3_uploads([upload]) + SiteSetting.secure_media = true end it "changes the upload to secure" do @@ -35,4 +35,20 @@ describe Jobs::UpdatePrivateUploadsAcl do end end end + + def enable_s3_uploads(uploads) + SiteSetting.enable_s3_uploads = true + SiteSetting.s3_upload_bucket = "s3-upload-bucket" + SiteSetting.s3_access_key_id = "some key" + SiteSetting.s3_secret_access_key = "some secrets3_region key" + + stub_request(:head, "https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com/") + + uploads.each do |upload| + stub_request( + :put, + "https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com/original/1X/#{upload.sha1}.#{upload.extension}?acl" + ) + end + end end diff --git a/spec/lib/upload_security_spec.rb b/spec/lib/upload_security_spec.rb index 3dc812bbdc..eabf061678 100644 --- a/spec/lib/upload_security_spec.rb +++ b/spec/lib/upload_security_spec.rb @@ -97,11 +97,20 @@ RSpec.describe UploadSecurity do context "when the access control post has_secure_media?" do before do - upload.update(access_control_post: post_in_secure_context) + upload.update(access_control_post_id: post_in_secure_context.id) end it "returns true" do expect(subject.should_be_secure?).to eq(true) end + + context "when the post is deleted" do + before do + post_in_secure_context.trash! + end + it "still determines whether the post has secure media; returns true" do + expect(subject.should_be_secure?).to eq(true) + end + end end context "when uploading in the composer" do diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index e2e278bb91..ad5fe6873e 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -130,6 +130,10 @@ module Helpers def capture_stdout old_stdout = $stdout + if ENV['RAILS_ENABLE_TEST_STDOUT'] + yield + return + end io = StringIO.new $stdout = io yield diff --git a/spec/tasks/uploads_spec.rb b/spec/tasks/uploads_spec.rb index 944c78b5a0..21c769a092 100644 --- a/spec/tasks/uploads_spec.rb +++ b/spec/tasks/uploads_spec.rb @@ -6,9 +6,10 @@ RSpec.describe "tasks/uploads" do before do Rake::Task.clear Discourse::Application.load_tasks + SiteSetting.authorized_extensions += "|pdf" end - describe "uploads:ensure_correct_acl" do + describe "uploads:secure_upload_analyse_and_update" do let!(:uploads) do [ multi_post_upload1, @@ -19,6 +20,7 @@ RSpec.describe "tasks/uploads" do let(:multi_post_upload1) { Fabricate(:upload_s3) } let(:upload1) { Fabricate(:upload_s3) } let(:upload2) { Fabricate(:upload_s3) } + let(:upload3) { Fabricate(:upload_s3, original_filename: 'test.pdf') } let!(:post1) { Fabricate(:post) } let!(:post2) { Fabricate(:post) } @@ -29,11 +31,12 @@ RSpec.describe "tasks/uploads" do PostUpload.create(post: post2, upload: multi_post_upload1) PostUpload.create(post: post2, upload: upload1) PostUpload.create(post: post3, upload: upload2) + PostUpload.create(post: post3, upload: upload3) end def invoke_task capture_stdout do - Rake::Task['uploads:ensure_correct_acl'].invoke + Rake::Task['uploads:secure_upload_analyse_and_update'].invoke end end @@ -59,6 +62,7 @@ RSpec.describe "tasks/uploads" do expect(multi_post_upload1.reload.access_control_post).to eq(post1) expect(upload1.reload.access_control_post).to eq(post2) expect(upload2.reload.access_control_post).to eq(post3) + expect(upload3.reload.access_control_post).to eq(post3) end it "sets the upload in the read restricted topic category to secure" do @@ -66,6 +70,7 @@ RSpec.describe "tasks/uploads" do invoke_task expect(upload2.reload.secure).to eq(true) expect(upload1.reload.secure).to eq(false) + expect(upload3.reload.secure).to eq(false) end it "sets the upload in the PM topic to secure" do @@ -86,10 +91,95 @@ RSpec.describe "tasks/uploads" do expect(post2.reload.baked_at).not_to eq(post2_baked) expect(post3.reload.baked_at).not_to eq(post3_baked) end + + context "for an upload that is already secure and does not need to change" do + before do + post3.topic.update(archetype: 'private_message', category: nil) + upload2.update(access_control_post: post3) + upload2.update_secure_status + end + + it "does not rebake the associated post" do + post3_baked = post3.baked_at.to_s + invoke_task + expect(post3.reload.baked_at.to_s).to eq(post3_baked) + end + + it "does not attempt to update the acl" do + Discourse.store.expects(:update_upload_ACL).with(upload2).never + invoke_task + end + end + + context "for an upload that is already secure and is changing to not secure" do + it "changes the upload to not secure and updates the ACL" do + upload_to_mark_not_secure = Fabricate(:upload_s3, secure: true) + post_for_upload = Fabricate(:post) + PostUpload.create(post: post_for_upload, upload: upload_to_mark_not_secure) + enable_s3_uploads(uploads.concat([upload_to_mark_not_secure])) + invoke_task + expect(upload_to_mark_not_secure.reload.secure).to eq(false) + end + end end end end + describe "uploads:disable_secure_media" do + def invoke_task + capture_stdout do + Rake::Task['uploads:disable_secure_media'].invoke + end + end + + before do + enable_s3_uploads(uploads) + SiteSetting.secure_media = true + PostUpload.create(post: post1, upload: upload1) + PostUpload.create(post: post1, upload: upload2) + PostUpload.create(post: post2, upload: upload3) + PostUpload.create(post: post2, upload: upload4) + end + + let!(:uploads) do + [ + upload1, upload2, upload3, upload4, upload5 + ] + end + let(:post1) { Fabricate(:post) } + let(:post2) { Fabricate(:post) } + let(:upload1) { Fabricate(:upload_s3, secure: true, access_control_post: post1) } + let(:upload2) { Fabricate(:upload_s3, secure: true, access_control_post: post1) } + let(:upload3) { Fabricate(:upload_s3, secure: true, access_control_post: post2) } + let(:upload4) { Fabricate(:upload_s3, secure: true, access_control_post: post2) } + let(:upload5) { Fabricate(:upload_s3, secure: false) } + + it "disables the secure media setting" do + invoke_task + expect(SiteSetting.secure_media).to eq(false) + end + + it "updates all secure uploads to secure: false" do + invoke_task + [upload1, upload2, upload3, upload4].each do |upl| + expect(upl.reload.secure).to eq(false) + end + end + + it "rebakes the associated posts" do + baked_post1 = post1.baked_at + baked_post2 = post2.baked_at + invoke_task + expect(post1.reload.baked_at).not_to eq(baked_post1) + expect(post2.reload.baked_at).not_to eq(baked_post2) + end + + it "updates the affected ACLs" do + FileStore::S3Store.any_instance.expects(:update_upload_ACL).times(4) + invoke_task + end + end + def enable_s3_uploads(uploads) SiteSetting.enable_s3_uploads = true SiteSetting.s3_upload_bucket = "s3-upload-bucket" From 5035a490b2f6f93d50f36f0c7d9e404b3f170ac5 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 3 Mar 2020 07:02:01 +0300 Subject: [PATCH 0062/1830] DEV: Bump Logster version to 2.7.1 This version includes a fix to stop `env` mutation that occurred in Logster default store which caused chained loggers to report different backtraces for the same message when backtrace is provided via `env`. https://github.com/discourse/logster/compare/v2.7.0...v2.7.1 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1134290d72..c100806191 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -171,7 +171,7 @@ GEM logstash-event (1.2.02) logstash-logger (0.26.1) logstash-event (~> 1.2) - logster (2.7.0) + logster (2.7.1) loofah (2.4.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) From 0df72a51b89a07fa57856d2774c6f6f17609740b Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Tue, 3 Mar 2020 15:44:01 +1100 Subject: [PATCH 0063/1830] FIX: Stop infinite lookup-urls issue for video/audio on page (#9096) Meta report: https://meta.discourse.org/t/excessive-requests-to-uploads-lookup-urls-leading-to-429-response/143119 * The data-orig-src attribute was not being removed from cooked video and audio so the composer was infinitely trying to get the URLs for them, which would never resolve to anything * Also the code that retrieved the short URL was unscoped, and was getting everything on the page. if running from the composer we now scope to the preview window * Also fixed a minor issue where the element href for the video and audio tags was not being set when the short URL was found --- .../components/composer-editor.js.es6 | 2 +- .../engines/discourse-markdown-it.js.es6 | 6 ++- .../pretty-text/upload-short-url.js.es6 | 29 ++++++++--- test/javascripts/lib/pretty-text-test.js.es6 | 50 +++++++++++++++++++ .../lib/upload-short-url-test.js.es6 | 28 ++++++++++- 5 files changed, 103 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 24c71dd8fb..5a47546093 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -1014,7 +1014,7 @@ export default Component.extend({ ); // Short upload urls need resolution - resolveAllShortUrls(ajax); + resolveAllShortUrls(ajax, ".d-editor-preview-wrapper"); if (this._enableAdvancedEditorPreviewSync()) { this._syncScroll( diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6 index 6e6392d774..213aef39d9 100644 --- a/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6 +++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown-it.js.es6 @@ -145,9 +145,10 @@ function videoHTML(token, opts) { const src = token.attrGet("src"); const origSrc = token.attrGet("data-orig-src"); const preloadType = opts.secureMedia ? "none" : "metadata"; + const dataOrigSrcAttr = origSrc !== null ? `data-orig-src="${origSrc}"` : ""; return `
`; @@ -157,8 +158,9 @@ function audioHTML(token, opts) { const src = token.attrGet("src"); const origSrc = token.attrGet("data-orig-src"); const preloadType = opts.secureMedia ? "none" : "metadata"; + const dataOrigSrcAttr = origSrc !== null ? `data-orig-src="${origSrc}"` : ""; return ``; } diff --git a/app/assets/javascripts/pretty-text/upload-short-url.js.es6 b/app/assets/javascripts/pretty-text/upload-short-url.js.es6 index b82e524173..294bae54de 100644 --- a/app/assets/javascripts/pretty-text/upload-short-url.js.es6 +++ b/app/assets/javascripts/pretty-text/upload-short-url.js.es6 @@ -9,6 +9,11 @@ export function lookupCachedUploadUrl(shortUrl) { const MISSING = "missing"; export function lookupUncachedUploadUrls(urls, ajax) { + urls = _.compact(urls); + if (urls.length === 0) { + return; + } + return ajax("/uploads/lookup-urls", { method: "POST", data: { short_urls: urls } @@ -77,7 +82,7 @@ function _loadCachedShortUrls($uploads) { }); break; - case "SOURCE": // video tag > source tag + case "SOURCE": // video/audio tag > source tag retrieveCachedUrl($upload, "orig-src", url => { $upload.attr("src", url); @@ -85,11 +90,19 @@ function _loadCachedShortUrls($uploads) { let hostRegex = new RegExp("//" + window.location.host, "g"); url = url.replace(hostRegex, ""); } - $upload.attr("src", window.location.origin + url); + let fullUrl = window.location.origin + url; + $upload.attr("src", fullUrl); // this is necessary, otherwise because of the src change the - // video just doesn't bother loading! - $upload.parent()[0].load(); + // video/audio just doesn't bother loading! + let $parent = $upload.parent(); + $parent[0].load(); + + // set the url and text for the tag within the

`, + "It returns the correct video HTML when the URL is mapped with secure media, removing data-orig-src" + ); +}); + QUnit.test("audio", assert => { assert.cooked( "![young americans|audio](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3)", @@ -1023,6 +1049,30 @@ QUnit.test("audio", assert => { ); }); +QUnit.test("audio - mapped url - secure media enabled", assert => { + function lookupUploadUrls() { + let cache = {}; + cache["upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3"] = { + short_url: "upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3", + url: "/secure-media-uploads/original/3X/c/b/test.mp3", + short_path: "/uploads/short-url/blah" + }; + return cache; + } + assert.cookedOptions( + "![baby shark|audio](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp3)", + { + siteSettings: { secure_media: true }, + lookupUploadUrls: lookupUploadUrls + }, + `

`, + "It returns the correct audio HTML when the URL is mapped with secure media, removing data-orig-src" + ); +}); + QUnit.test("censoring", assert => { assert.cookedOptions( "Pleased to meet you, but pleeeease call me later, xyz123", diff --git a/test/javascripts/lib/upload-short-url-test.js.es6 b/test/javascripts/lib/upload-short-url-test.js.es6 index 39a5e7b000..f0521a174b 100644 --- a/test/javascripts/lib/upload-short-url-test.js.es6 +++ b/test/javascripts/lib/upload-short-url-test.js.es6 @@ -23,6 +23,11 @@ QUnit.module("lib:pretty-text/upload-short-url", { short_url: "upload://b.jpeg", url: "/uploads/default/original/3X/c/b/2.jpeg", short_path: "/uploads/short-url/b.jpeg" + }, + { + short_url: "upload://z.jpeg", + url: "/uploads/default/original/3X/c/b/9.jpeg", + short_path: "/uploads/short-url/z.jpeg" } ]; @@ -53,7 +58,8 @@ QUnit.module("lib:pretty-text/upload-short-url", { fixture().html( imageSrcs.map(src => ``).join("") + - attachmentSrcs.map(src => ``).join("") + attachmentSrcs.map(src => ``).join("") + + `
` ); }, @@ -105,3 +111,23 @@ QUnit.test("resolveAllShortUrls", async assert => { short_path: "/uploads/short-url/e.mp3" }); }); + +QUnit.test("resolveAllShortUrls - scoped", async assert => { + let lookup; + await resolveAllShortUrls(ajax, ".scoped-area"); + + lookup = lookupCachedUploadUrl("upload://z.jpeg"); + + assert.deepEqual(lookup, { + url: "/uploads/default/original/3X/c/b/9.jpeg", + short_path: "/uploads/short-url/z.jpeg" + }); + + // do this because the pretender caches ALL the urls, not + // just the ones being looked up (like the normal behaviour) + resetCache(); + await resolveAllShortUrls(ajax, ".scoped-area"); + + lookup = lookupCachedUploadUrl("upload://a.jpeg"); + assert.deepEqual(lookup, {}); +}); From d23f7af3cbe8d9bc7c07db01ff7fb72275943174 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 3 Mar 2020 13:56:54 +0000 Subject: [PATCH 0064/1830] PERF: Allow user serializer to make use of preloaded custom fields (#9074) --- app/models/concerns/has_custom_fields.rb | 4 ++++ app/serializers/user_card_serializer.rb | 19 +++++++++++++------ app/serializers/user_serializer.rb | 12 ++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/app/models/concerns/has_custom_fields.rb b/app/models/concerns/has_custom_fields.rb index 923efe846d..64cafe6f7a 100644 --- a/app/models/concerns/has_custom_fields.rb +++ b/app/models/concerns/has_custom_fields.rb @@ -142,6 +142,10 @@ module HasCustomFields super end + def custom_fields_preloaded? + !!@preloaded_custom_fields + end + def custom_field_preloaded?(name) @preloaded_custom_fields && @preloaded_custom_fields.key?(name) end diff --git a/app/serializers/user_card_serializer.rb b/app/serializers/user_card_serializer.rb index 5d53a6258c..6b7f59cd40 100644 --- a/app/serializers/user_card_serializer.rb +++ b/app/serializers/user_card_serializer.rb @@ -149,14 +149,14 @@ class UserCardSerializer < BasicUserSerializer end def custom_fields - fields = User.whitelisted_user_custom_fields(scope) - - if scope.can_edit?(object) - fields += DiscoursePluginRegistry.serialized_current_user_fields.to_a - end + fields = custom_field_keys if fields.present? - User.custom_fields_for_ids([object.id], fields)[object.id] || {} + if object.custom_fields_preloaded? + {}.tap { |h| fields.each { |f| h[f] = object.custom_fields[f] } } + else + User.custom_fields_for_ids([object.id], fields)[object.id] || {} + end else {} end @@ -197,4 +197,11 @@ class UserCardSerializer < BasicUserSerializer def card_background_upload_url object.card_background_upload&.url end + + private + + def custom_field_keys + # Can be extended by other serializers + User.whitelisted_user_custom_fields(scope) + end end diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index d92f0e4224..866dc39a8d 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -270,4 +270,16 @@ class UserSerializer < UserCardSerializer object.profile_background_upload&.url end + private + + def custom_field_keys + fields = super + + if scope.can_edit?(object) + fields += DiscoursePluginRegistry.serialized_current_user_fields.to_a + end + + fields + end + end From 65cc61be7a3be78a682cfe9f72f99f4ed7374264 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 3 Mar 2020 13:57:46 +0000 Subject: [PATCH 0065/1830] PERF: Allow preloading 'recent time read' for a user (#9076) This will be used when serializing multiple user cards --- app/models/user.rb | 18 +++++++++++++++--- spec/models/user_spec.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index e8cc35f891..fd81a979d0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1211,10 +1211,22 @@ class User < ActiveRecord::Base self.user_emails.secondary.pluck(:email) end + RECENT_TIME_READ_THRESHOLD ||= 60.days + + def self.preload_recent_time_read(users) + times = UserVisit.where(user_id: users.map(&:id)) + .where('visited_at >= ?', RECENT_TIME_READ_THRESHOLD.ago) + .group(:user_id) + .sum(:time_read) + users.each { |u| u.preload_recent_time_read(times[u.id] || 0) } + end + + def preload_recent_time_read(time) + @recent_time_read = time + end + def recent_time_read - self.created_at && self.created_at < 60.days.ago ? - self.user_visits.where('visited_at >= ?', 60.days.ago).sum(:time_read) : - self.user_stat&.time_read + @recent_time_read ||= self.user_visits.where('visited_at >= ?', RECENT_TIME_READ_THRESHOLD.ago).sum(:time_read) end def from_staged? diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index ee1bea598a..d23451fcfa 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -2287,4 +2287,32 @@ describe User do expect(user.approved).to eq(true) end end + + describe "#recent_time_read" do + fab!(:user) { Fabricate(:user) } + fab!(:user2) { Fabricate(:user) } + + before_all do + UserVisit.create(user_id: user.id, visited_at: 1.minute.ago, posts_read: 1, mobile: false, time_read: 10) + UserVisit.create(user_id: user.id, visited_at: 2.days.ago, posts_read: 1, mobile: false, time_read: 20) + UserVisit.create(user_id: user.id, visited_at: 1.week.ago, posts_read: 1, mobile: false, time_read: 30) + UserVisit.create(user_id: user.id, visited_at: 1.year.ago, posts_read: 1, mobile: false, time_read: 40) # Old, should be ignored + UserVisit.create(user_id: user2.id, visited_at: 1.minute.ago, posts_read: 1, mobile: false, time_read: 50) + end + + it "calculates correctly" do + expect(user.recent_time_read).to eq(60) + expect(user2.recent_time_read).to eq(50) + end + + it "preloads correctly" do + User.preload_recent_time_read([user, user2]) + + expect(user.instance_variable_get(:@recent_time_read)).to eq(60) + expect(user2.instance_variable_get(:@recent_time_read)).to eq(50) + + expect(user.recent_time_read).to eq(60) + expect(user2.recent_time_read).to eq(50) + end + end end From f971ecd2316cfb62d164068deaa7b51587fa2cd7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 3 Mar 2020 10:19:34 -0500 Subject: [PATCH 0066/1830] Build(deps): Bump nokogiri from 1.10.8 to 1.10.9 (#9093) Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.10.8 to 1.10.9. - [Release notes](https://github.com/sparklemotion/nokogiri/releases) - [Changelog](https://github.com/sparklemotion/nokogiri/blob/v1.10.9/CHANGELOG.md) - [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.10.8...v1.10.9) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index c100806191..ef5d694e5d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -204,7 +204,7 @@ GEM multipart-post (2.1.1) mustache (1.1.1) nio4r (2.5.2) - nokogiri (1.10.8) + nokogiri (1.10.9) mini_portile2 (~> 2.4.0) nokogumbo (2.0.2) nokogiri (~> 1.8, >= 1.8.4) From 3e54e0191e05deee9e6b20caf224463e3e86f7a5 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Wed, 4 Mar 2020 10:11:08 +1100 Subject: [PATCH 0067/1830] FIX: Use full URL for secure attachments when secure media enabled (#9037) When secure media is enabled and an attachment is marked as secure we want to use the full url instead of the short-url so we get the same access control post protections as secure media uploads. --- .../components/composer-editor.js.es6 | 2 +- .../discourse/components/cook-text.js.es6 | 2 +- .../discourse-markdown/upload-protocol.js.es6 | 11 ++- .../pretty-text/upload-short-url.js.es6 | 45 ++++++--- lib/pretty_text/helpers.rb | 2 +- spec/requests/uploads_controller_spec.rb | 4 +- .../composer-attachment-test.js.es6 | 60 +++++++++--- test/javascripts/helpers/site-settings.js | 3 +- test/javascripts/lib/pretty-text-test.js.es6 | 52 ++++++++++ .../lib/upload-short-url-test.js.es6 | 97 +++++++++++++++---- 10 files changed, 223 insertions(+), 55 deletions(-) diff --git a/app/assets/javascripts/discourse/components/composer-editor.js.es6 b/app/assets/javascripts/discourse/components/composer-editor.js.es6 index 5a47546093..52f44e78f5 100644 --- a/app/assets/javascripts/discourse/components/composer-editor.js.es6 +++ b/app/assets/javascripts/discourse/components/composer-editor.js.es6 @@ -1014,7 +1014,7 @@ export default Component.extend({ ); // Short upload urls need resolution - resolveAllShortUrls(ajax, ".d-editor-preview-wrapper"); + resolveAllShortUrls(ajax, this.siteSettings, ".d-editor-preview-wrapper"); if (this._enableAdvancedEditorPreviewSync()) { this._syncScroll( diff --git a/app/assets/javascripts/discourse/components/cook-text.js.es6 b/app/assets/javascripts/discourse/components/cook-text.js.es6 index 256636a3c5..f3ad48f549 100644 --- a/app/assets/javascripts/discourse/components/cook-text.js.es6 +++ b/app/assets/javascripts/discourse/components/cook-text.js.es6 @@ -16,7 +16,7 @@ const CookText = Component.extend({ next(() => window .requireModule("pretty-text/upload-short-url") - .resolveAllShortUrls(ajax) + .resolveAllShortUrls(ajax, this.siteSettings) ); }); } diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6 b/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6 index 3e075b13ac..174e603212 100644 --- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6 +++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/upload-protocol.js.es6 @@ -60,7 +60,16 @@ function rule(state) { break; case "a": if (mapped) { - token.attrs[srcIndex][1] = mapped.short_path; + // when secure media is enabled we want the full /secure-media-uploads/ + // url to take advantage of access control security + if ( + state.md.options.discourse.limitedSiteSettings.secureMedia && + mapped.url.indexOf("secure-media-uploads") > -1 + ) { + token.attrs[srcIndex][1] = mapped.url; + } else { + token.attrs[srcIndex][1] = mapped.short_path; + } } else { token.attrs[srcIndex][1] = state.md.options.discourse.getURL( "/404" diff --git a/app/assets/javascripts/pretty-text/upload-short-url.js.es6 b/app/assets/javascripts/pretty-text/upload-short-url.js.es6 index 294bae54de..401d73dff0 100644 --- a/app/assets/javascripts/pretty-text/upload-short-url.js.es6 +++ b/app/assets/javascripts/pretty-text/upload-short-url.js.es6 @@ -44,10 +44,9 @@ export function resetCache() { _cache = {}; } -function retrieveCachedUrl($upload, dataAttribute, callback) { +function retrieveCachedUrl($upload, siteSettings, dataAttribute, callback) { const cachedUpload = lookupCachedUploadUrl($upload.data(dataAttribute)); - const url = - dataAttribute === "orig-href" ? cachedUpload.short_path : cachedUpload.url; + const url = getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings); if (url) { $upload.removeAttr(`data-${dataAttribute}`); @@ -57,12 +56,34 @@ function retrieveCachedUrl($upload, dataAttribute, callback) { } } -function _loadCachedShortUrls($uploads) { +function getAttributeBasedUrl(dataAttribute, cachedUpload, siteSettings) { + if (!cachedUpload.url) { + return; + } + + // non-attachments always use the full URL + if (dataAttribute !== "orig-href") { + return cachedUpload.url; + } + + // attachments should use the full /secure-media-uploads/ URL + // in this case for permission checks + if ( + siteSettings.secure_media && + cachedUpload.url.indexOf("secure-media-uploads") > -1 + ) { + return cachedUpload.url; + } + + return cachedUpload.short_path; +} + +function _loadCachedShortUrls($uploads, siteSettings) { $uploads.each((_idx, upload) => { const $upload = $(upload); switch (upload.tagName) { case "A": - retrieveCachedUrl($upload, "orig-href", url => { + retrieveCachedUrl($upload, siteSettings, "orig-href", url => { $upload.attr("href", url); // Replace "|attachment" with class='attachment' @@ -77,13 +98,13 @@ function _loadCachedShortUrls($uploads) { break; case "IMG": - retrieveCachedUrl($upload, "orig-src", url => { + retrieveCachedUrl($upload, siteSettings, "orig-src", url => { $upload.attr("src", url); }); break; case "SOURCE": // video/audio tag > source tag - retrieveCachedUrl($upload, "orig-src", url => { + retrieveCachedUrl($upload, siteSettings, "orig-src", url => { $upload.attr("src", url); if (url.startsWith(`//${window.location.host}`)) { @@ -110,31 +131,31 @@ function _loadCachedShortUrls($uploads) { }); } -function _loadShortUrls($uploads, ajax) { +function _loadShortUrls($uploads, ajax, siteSettings) { let urls = $uploads.toArray().map(upload => { const $upload = $(upload); return $upload.data("orig-src") || $upload.data("orig-href"); }); return lookupUncachedUploadUrls(urls, ajax).then(() => - _loadCachedShortUrls($uploads) + _loadCachedShortUrls($uploads, siteSettings) ); } -export function resolveAllShortUrls(ajax, scope = null) { +export function resolveAllShortUrls(ajax, siteSettings, scope = null) { const attributes = "img[data-orig-src], a[data-orig-href], source[data-orig-src]"; let $shortUploadUrls = $(scope || document).find(attributes); if ($shortUploadUrls.length > 0) { - _loadCachedShortUrls($shortUploadUrls); + _loadCachedShortUrls($shortUploadUrls, siteSettings); $shortUploadUrls = $(scope || document).find(attributes); if ($shortUploadUrls.length > 0) { // this is carefully batched so we can do a leading debounce (trigger right away) return debounce( null, - () => _loadShortUrls($shortUploadUrls, ajax), + () => _loadShortUrls($shortUploadUrls, ajax, siteSettings), 450, true ); diff --git a/lib/pretty_text/helpers.rb b/lib/pretty_text/helpers.rb index 0de6000fea..d207e01eed 100644 --- a/lib/pretty_text/helpers.rb +++ b/lib/pretty_text/helpers.rb @@ -68,7 +68,7 @@ module PrettyText sha1, url, extension, original_filename, secure = row if short_urls = reverse_map[sha1] - secure_media = FileHelper.is_supported_media?(original_filename) && SiteSetting.secure_media? && secure + secure_media = SiteSetting.secure_media? && secure short_urls.each do |short_url| result[short_url] = { diff --git a/spec/requests/uploads_controller_spec.rb b/spec/requests/uploads_controller_spec.rb index e27a4d4671..2f3333cacd 100644 --- a/spec/requests/uploads_controller_spec.rb +++ b/spec/requests/uploads_controller_spec.rb @@ -578,7 +578,7 @@ describe UploadsController do expect(result[0]["short_path"]).to eq(upload.short_path) end - it 'does not return secure urls for non-media uploads' do + it 'returns secure urls for non-media uploads' do upload.update!(original_filename: "not-an-image.pdf", extension: "pdf") sign_in(user) @@ -586,7 +586,7 @@ describe UploadsController do expect(response.status).to eq(200) result = JSON.parse(response.body) - expect(result[0]["url"]).not_to match("/secure-media-uploads") + expect(result[0]["url"]).to match("/secure-media-uploads") expect(result[0]["short_path"]).to eq(upload.short_path) end end diff --git a/test/javascripts/acceptance/composer-attachment-test.js.es6 b/test/javascripts/acceptance/composer-attachment-test.js.es6 index edf6bc4374..0333936f4b 100644 --- a/test/javascripts/acceptance/composer-attachment-test.js.es6 +++ b/test/javascripts/acceptance/composer-attachment-test.js.es6 @@ -1,21 +1,18 @@ import { acceptance } from "helpers/qunit-helpers"; -acceptance("Composer Attachment", { - loggedIn: true, - pretend(server, helper) { - server.post("/uploads/lookup-urls", () => { - return helper.response([ - { - short_url: "upload://asdsad.png", - url: "/uploads/default/3X/1/asjdiasjdiasida.png", - short_path: "/uploads/short-url/asdsad.png" - } - ]); - }); - } -}); +function setupPretender(server, helper) { + server.post("/uploads/lookup-urls", () => { + return helper.response([ + { + short_url: "upload://asdsad.png", + url: "/secure-media-uploads/default/3X/1/asjdiasjdiasida.png", + short_path: "/uploads/short-url/asdsad.png" + } + ]); + }); +} -QUnit.test("attachments are cooked properly", async assert => { +async function writeInComposer(assert) { await visit("/t/internationalization-localization/280"); await click("#topic-footer-buttons .btn.create"); @@ -29,7 +26,17 @@ QUnit.test("attachments are cooked properly", async assert => { ); await fillIn(".d-editor-input", "[test|attachment](upload://asdsad.png)"); +} +acceptance("Composer Attachment", { + loggedIn: true, + pretend(server, helper) { + setupPretender(server, helper); + } +}); + +QUnit.test("attachments are cooked properly", async assert => { + await writeInComposer(assert); assert.equal( find(".d-editor-preview:visible") .html() @@ -37,3 +44,26 @@ QUnit.test("attachments are cooked properly", async assert => { '

test

' ); }); + +acceptance("Composer Attachment - Secure Media Enabled", { + loggedIn: true, + settings: { + secure_media: true + }, + pretend(server, helper) { + setupPretender(server, helper); + } +}); + +QUnit.test( + "attachments are cooked properly when secure media is enabled", + async assert => { + await writeInComposer(assert); + assert.equal( + find(".d-editor-preview:visible") + .html() + .trim(), + '

test

' + ); + } +); diff --git a/test/javascripts/helpers/site-settings.js b/test/javascripts/helpers/site-settings.js index 96807b7a7c..621aa3d6ac 100644 --- a/test/javascripts/helpers/site-settings.js +++ b/test/javascripts/helpers/site-settings.js @@ -99,7 +99,8 @@ Discourse.SiteSettingsOriginal = { desktop_category_page_style: "categories_and_latest_topics", enable_mentions: true, enable_personal_messages: true, - unicode_usernames: false + unicode_usernames: false, + secure_media: false }; Discourse.SiteSettings = jQuery.extend( true, diff --git a/test/javascripts/lib/pretty-text-test.js.es6 b/test/javascripts/lib/pretty-text-test.js.es6 index 23708ddacb..7c75034529 100644 --- a/test/javascripts/lib/pretty-text-test.js.es6 +++ b/test/javascripts/lib/pretty-text-test.js.es6 @@ -973,6 +973,58 @@ QUnit.test("images", assert => { ); }); +QUnit.test("attachment", assert => { + assert.cooked( + "[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)", + `

test.pdf

`, + "It returns the correct attachment link HTML" + ); +}); + +QUnit.test("attachment - mapped url - secure media disabled", assert => { + function lookupUploadUrls() { + let cache = {}; + cache["upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf"] = { + short_url: "upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", + url: + "/secure-media-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", + short_path: "/uploads/short-url/blah" + }; + return cache; + } + assert.cookedOptions( + "[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)", + { + siteSettings: { secure_media: false }, + lookupUploadUrls: lookupUploadUrls + }, + `

test.pdf

`, + "It returns the correct attachment link HTML when the URL is mapped without secure media" + ); +}); + +QUnit.test("attachment - mapped url - secure media enabled", assert => { + function lookupUploadUrls() { + let cache = {}; + cache["upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf"] = { + short_url: "upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", + url: + "/secure-media-uploads/original/3X/c/b/o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf", + short_path: "/uploads/short-url/blah" + }; + return cache; + } + assert.cookedOptions( + "[test.pdf|attachment](upload://o8iobpLcW3WSFvVH7YQmyGlKmGM.pdf)", + { + siteSettings: { secure_media: true }, + lookupUploadUrls: lookupUploadUrls + }, + `

test.pdf

`, + "It returns the correct attachment link HTML when the URL is mapped with secure media" + ); +}); + QUnit.test("video - secure media enabled", assert => { assert.cookedOptions( "![baby shark|video](upload://eyPnj7UzkU0AkGkx2dx8G4YM1Jx.mp4)", diff --git a/test/javascripts/lib/upload-short-url-test.js.es6 b/test/javascripts/lib/upload-short-url-test.js.es6 index f0521a174b..849b2d7602 100644 --- a/test/javascripts/lib/upload-short-url-test.js.es6 +++ b/test/javascripts/lib/upload-short-url-test.js.es6 @@ -7,13 +7,12 @@ import { ajax } from "discourse/lib/ajax"; import { fixture } from "helpers/qunit-helpers"; import pretender from "helpers/create-pretender"; -QUnit.module("lib:pretty-text/upload-short-url", { - beforeEach() { - const response = object => { - return [200, { "Content-Type": "application/json" }, object]; - }; - - const imageSrcs = [ +function stubUrls(imageSrcs, attachmentSrcs, otherMediaSrcs) { + const response = object => { + return [200, { "Content-Type": "application/json" }, object]; + }; + if (!imageSrcs) { + imageSrcs = [ { short_url: "upload://a.jpeg", url: "/uploads/default/original/3X/c/b/1.jpeg", @@ -30,16 +29,20 @@ QUnit.module("lib:pretty-text/upload-short-url", { short_path: "/uploads/short-url/z.jpeg" } ]; + } - const attachmentSrcs = [ + if (!attachmentSrcs) { + attachmentSrcs = [ { short_url: "upload://c.pdf", url: "/uploads/default/original/3X/c/b/3.pdf", short_path: "/uploads/short-url/c.pdf" } ]; + } - const otherMediaSrcs = [ + if (!otherMediaSrcs) { + otherMediaSrcs = [ { short_url: "upload://d.mp4", url: "/uploads/default/original/3X/c/b/4.mp4", @@ -51,30 +54,37 @@ QUnit.module("lib:pretty-text/upload-short-url", { short_path: "/uploads/short-url/e.mp3" } ]; + } + // prettier-ignore + pretender.post("/uploads/lookup-urls", () => { //eslint-disable-line + return response(imageSrcs.concat(attachmentSrcs.concat(otherMediaSrcs))); + }); - pretender.post("/uploads/lookup-urls", () => { - return response(imageSrcs.concat(attachmentSrcs.concat(otherMediaSrcs))); - }); - - fixture().html( - imageSrcs.map(src => ``).join("") + - attachmentSrcs.map(src => ``).join("") + - `
` - ); - }, - + fixture().html( + imageSrcs.map(src => ``).join("") + + attachmentSrcs + .map( + src => + `
big enterprise contract.pdf` + ) + .join("") + + `
` + ); +} +QUnit.module("lib:pretty-text/upload-short-url", { afterEach() { resetCache(); } }); QUnit.test("resolveAllShortUrls", async assert => { + stubUrls(); let lookup; lookup = lookupCachedUploadUrl("upload://a.jpeg"); assert.deepEqual(lookup, {}); - await resolveAllShortUrls(ajax); + await resolveAllShortUrls(ajax, { secure_media: false }); lookup = lookupCachedUploadUrl("upload://a.jpeg"); @@ -112,7 +122,52 @@ QUnit.test("resolveAllShortUrls", async assert => { }); }); +QUnit.test( + "resolveAllShortUrls - href + src replaced correctly", + async assert => { + stubUrls(); + await resolveAllShortUrls(ajax, { secure_media: false }); + + let image1 = fixture() + .find("img") + .eq(0); + let image2 = fixture() + .find("img") + .eq(1); + let link = fixture().find("a"); + + assert.equal(image1.attr("src"), "/uploads/default/original/3X/c/b/1.jpeg"); + assert.equal(image2.attr("src"), "/uploads/default/original/3X/c/b/2.jpeg"); + assert.equal(link.attr("href"), "/uploads/short-url/c.pdf"); + } +); + +QUnit.test( + "resolveAllShortUrls - when secure media is enabled use the attachment full URL", + async assert => { + stubUrls( + null, + [ + { + short_url: "upload://c.pdf", + url: "/secure-media-uploads/default/original/3X/c/b/3.pdf", + short_path: "/uploads/short-url/c.pdf" + } + ], + null + ); + await resolveAllShortUrls(ajax, { secure_media: true }); + + let link = fixture().find("a"); + assert.equal( + link.attr("href"), + "/secure-media-uploads/default/original/3X/c/b/3.pdf" + ); + } +); + QUnit.test("resolveAllShortUrls - scoped", async assert => { + stubUrls(); let lookup; await resolveAllShortUrls(ajax, ".scoped-area"); From 97545ee4a0ef1bb0b98907494d7d80867f5b854d Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Tue, 3 Mar 2020 14:56:37 -1000 Subject: [PATCH 0068/1830] REFACTOR: separate post_can_act logic in post action creator (#9103) Package logic of the post can act a little bit better so that overriding methods can easily reuse the logic. --- lib/post_action_creator.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/post_action_creator.rb b/lib/post_action_creator.rb index 342ed5fd98..ab38576c8f 100644 --- a/lib/post_action_creator.rb +++ b/lib/post_action_creator.rb @@ -48,10 +48,8 @@ class PostActionCreator @meta_post = nil end - def perform - result = CreateResult.new - - unless guardian.post_can_act?( + def post_can_act? + guardian.post_can_act?( @post, @post_action_name, opts: { @@ -59,6 +57,12 @@ class PostActionCreator taken_actions: PostAction.counts_for([@post].compact, @created_by)[@post&.id] } ) + end + + def perform + result = CreateResult.new + + unless post_can_act? result.forbidden = true result.add_error(I18n.t("invalid_access")) return result From c457d3bf2851d70c87ce27aa316333b19f5bbed4 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 4 Mar 2020 16:48:06 +1100 Subject: [PATCH 0069/1830] FIX: under concurrent usage booting rails could cause plugin corruption Previously on boot we were always removing and adding the same pre-generated files and symlinks. This change attempts to avoid writing any automatically generated content if it is exactly what it should be on disk. This corrects issues where running a rails console can temporarily corrupt internal state in production. --- lib/plugin/instance.rb | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index b810a9dd78..837de08957 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -543,9 +543,17 @@ class Plugin::Instance Discourse::Utils.execute_command('mkdir', '-p', target) target << name.gsub(/\s/, "_") - # TODO a cleaner way of registering and unregistering - Discourse::Utils.execute_command('rm', '-f', target) - Discourse::Utils.execute_command('ln', '-s', public_data, target) + + symlink_is_correct = false + begin + symlink_is_correct = File.exists?(target) && File.readlink(target) == public_data + rescue Errno::EINVAL, Errno::ENOENT + end + + if !symlink_is_correct + Discourse::Utils.execute_command('rm', '-f', target) + Discourse::Utils.execute_command('ln', '-s', public_data, target) + end end ensure_directory(Plugin::Instance.js_path) @@ -558,12 +566,22 @@ class Plugin::Instance contents << (is_dir ? "depend_on('#{f}')" : "require_asset('#{f}')") end - File.delete(js_file_path) if js_asset_exists? - if contents.present? contents.insert(0, "<%") contents << "%>" - write_asset(js_file_path, contents.join("\n")) + + contents = contents.join("\n") + + if File.exists?(js_file_path) + current_contents = File.read(js_file_path) + if current_contents != contents + File.write(js_file_path, conten) + end + else + write_asset(js_file_path, contents) + end + else + File.delete(js_file_path) if js_asset_exists? end end From dae5b3d673e46c1d4192cef0a9f7b074825f9827 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 4 Mar 2020 16:55:53 +1100 Subject: [PATCH 0070/1830] DEV: correct typo in param name Followup to c457d3bf It did cause a test suite failure as expected --- lib/plugin/instance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 837de08957..4278382de7 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -575,7 +575,7 @@ class Plugin::Instance if File.exists?(js_file_path) current_contents = File.read(js_file_path) if current_contents != contents - File.write(js_file_path, conten) + File.write(js_file_path, contents) end else write_asset(js_file_path, contents) From 0054ccc52290fa973d66bdd1fcc74a0cd886ee01 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 4 Mar 2020 17:10:14 +1100 Subject: [PATCH 0071/1830] Revert "DEV: correct typo in param name" This reverts commit dae5b3d673e46c1d4192cef0a9f7b074825f9827. Something is not right about my fix reverting --- lib/plugin/instance.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 4278382de7..837de08957 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -575,7 +575,7 @@ class Plugin::Instance if File.exists?(js_file_path) current_contents = File.read(js_file_path) if current_contents != contents - File.write(js_file_path, contents) + File.write(js_file_path, conten) end else write_asset(js_file_path, contents) From 9cbed7ee465412b27b8a1a62a7001b470a984158 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 4 Mar 2020 17:10:36 +1100 Subject: [PATCH 0072/1830] Revert "FIX: under concurrent usage booting rails could cause plugin corruption" This reverts commit c457d3bf2851d70c87ce27aa316333b19f5bbed4. Something is not right about this fix, reverting. --- lib/plugin/instance.rb | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 837de08957..b810a9dd78 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -543,17 +543,9 @@ class Plugin::Instance Discourse::Utils.execute_command('mkdir', '-p', target) target << name.gsub(/\s/, "_") - - symlink_is_correct = false - begin - symlink_is_correct = File.exists?(target) && File.readlink(target) == public_data - rescue Errno::EINVAL, Errno::ENOENT - end - - if !symlink_is_correct - Discourse::Utils.execute_command('rm', '-f', target) - Discourse::Utils.execute_command('ln', '-s', public_data, target) - end + # TODO a cleaner way of registering and unregistering + Discourse::Utils.execute_command('rm', '-f', target) + Discourse::Utils.execute_command('ln', '-s', public_data, target) end ensure_directory(Plugin::Instance.js_path) @@ -566,22 +558,12 @@ class Plugin::Instance contents << (is_dir ? "depend_on('#{f}')" : "require_asset('#{f}')") end + File.delete(js_file_path) if js_asset_exists? + if contents.present? contents.insert(0, "<%") contents << "%>" - - contents = contents.join("\n") - - if File.exists?(js_file_path) - current_contents = File.read(js_file_path) - if current_contents != contents - File.write(js_file_path, conten) - end - else - write_asset(js_file_path, contents) - end - else - File.delete(js_file_path) if js_asset_exists? + write_asset(js_file_path, contents.join("\n")) end end From 93b8b04b068871ccdf9592e42cc310cfc49ee5f8 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Wed, 4 Mar 2020 12:46:04 +0100 Subject: [PATCH 0073/1830] FIX: Migrating uploads to S3 could miss files The rake task aborted the migration with "Already migrated" when all upload URLs linked to the correct S3 bucket even though the files didn't exist on S3. By removing the first check we force the rake task to check for the existance of uploads on S3. --- lib/file_store/to_s3_migration.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/file_store/to_s3_migration.rb b/lib/file_store/to_s3_migration.rb index fe2edd5a53..456e428657 100644 --- a/lib/file_store/to_s3_migration.rb +++ b/lib/file_store/to_s3_migration.rb @@ -139,9 +139,6 @@ module FileStore # we don't want have migrated state, ensure we run all jobs here Jobs.run_immediately! - log "Checking if #{@current_db} already migrated..." - return log "Already migrated #{@current_db}!" if migration_successful? - log "*" * 30 + " DRY RUN " + "*" * 30 if @dry_run log "Migrating uploads to S3 for '#{@current_db}'..." From 33f77e51b839138f1e866731b034b3b2d980d6f1 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 4 Mar 2020 15:32:15 +0100 Subject: [PATCH 0074/1830] FIX: allows to select the action when agreeing with penalty (#9099) Note this commit also fixes an issue where the edit post actions was trying to focus the edit textarea, but was using jquery functions on a DOM node. scrollTo is not available on IE11 but that shouldn't cause much trouble. --- .../components/penalty-post-action.js.es6 | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 b/app/assets/javascripts/admin/components/penalty-post-action.js.es6 index 09f267390c..916546452c 100644 --- a/app/assets/javascripts/admin/components/penalty-post-action.js.es6 +++ b/app/assets/javascripts/admin/components/penalty-post-action.js.es6 @@ -1,7 +1,7 @@ import discourseComputed from "discourse-common/utils/decorators"; import { equal } from "@ember/object/computed"; -import { scheduleOnce } from "@ember/runloop"; import Component from "@ember/component"; +import { afterRender } from "discourse-common/utils/decorators"; const ACTIONS = ["delete", "delete_replies", "edit", "none"]; @@ -20,16 +20,21 @@ export default Component.extend({ editing: equal("postAction", "edit"), actions: { - penaltyChanged() { + penaltyChanged(postAction) { + this.set("postAction", postAction); + // If we switch to edit mode, jump to the edit textarea - if (this.postAction === "edit") { - scheduleOnce("afterRender", () => { - const elem = this.element; - const body = elem.closest(".modal-body"); - body.scrollTop(body.height()); - elem.querySelector(".post-editor").focus(); - }); + if (postAction === "edit") { + this._focusEditTextarea(); } } + }, + + @afterRender + _focusEditTextarea() { + const elem = this.element; + const body = elem.closest(".modal-body"); + body.scrollTo(0, body.clientHeight); + elem.querySelector(".post-editor").focus(); } }); From 5c581b475a6d88a62257b7af1fe39c2cf0dde96e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2020 10:06:13 -0500 Subject: [PATCH 0075/1830] Build(deps): Bump oj from 3.10.3 to 3.10.5 (#9107) Bumps [oj](https://github.com/ohler55/oj) from 3.10.3 to 3.10.5. - [Release notes](https://github.com/ohler55/oj/releases) - [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ohler55/oj/compare/v3.10.3...v3.10.5) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index ef5d694e5d..5d4ea41328 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -215,7 +215,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.10.3) + oj (3.10.5) omniauth (1.9.0) hashie (>= 3.4.6, < 3.7.0) rack (>= 1.6.2, < 3) From 8fa8bab9ff361bfa36592a6e32cfb96a4fc38d06 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Wed, 4 Mar 2020 16:57:16 +0100 Subject: [PATCH 0076/1830] FIX: Don't optimize icons during db:migrate when restoring backup Uploads are extracted after the DB migration, so this could lead to a failure during the restore. Site icons get optimized after extracting uploads. --- lib/backup_restore/database_restorer.rb | 2 +- lib/tasks/db.rake | 2 +- spec/lib/backup_restore/database_restorer_spec.rb | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/backup_restore/database_restorer.rb b/lib/backup_restore/database_restorer.rb index b3cb9ab0c8..d0880c97ed 100644 --- a/lib/backup_restore/database_restorer.rb +++ b/lib/backup_restore/database_restorer.rb @@ -134,7 +134,7 @@ module BackupRestore log "Migrating the database..." log Discourse::Utils.execute_command( - { "SKIP_POST_DEPLOYMENT_MIGRATIONS" => "0" }, + { "SKIP_POST_DEPLOYMENT_MIGRATIONS" => "0", "SKIP_OPTIMIZE_ICONS" => "1" }, "rake db:migrate", failure_message: "Failed to migrate database.", chdir: Rails.root diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 626acd5760..df830da6ac 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -77,7 +77,7 @@ task 'db:migrate' => ['load_config', 'environment', 'set_locale'] do |_, args| SeedFu.seed(DiscoursePluginRegistry.seed_paths) - if !Discourse.skip_post_deployment_migrations? + if !Discourse.skip_post_deployment_migrations? && ENV['SKIP_OPTIMIZE_ICONS'] != '1' puts print "Optimizing site icons... " SiteIconManager.ensure_optimized! diff --git a/spec/lib/backup_restore/database_restorer_spec.rb b/spec/lib/backup_restore/database_restorer_spec.rb index 6d79dff9ef..02666093b0 100644 --- a/spec/lib/backup_restore/database_restorer_spec.rb +++ b/spec/lib/backup_restore/database_restorer_spec.rb @@ -37,6 +37,7 @@ describe BackupRestore::DatabaseRestorer do def expect_db_migrate Discourse::Utils.expects(:execute_command).with do |env, command, options| env["SKIP_POST_DEPLOYMENT_MIGRATIONS"] == "0" && + env["SKIP_OPTIMIZE_ICONS"] == "1" && command == "rake db:migrate" && options[:chdir] == Rails.root end.once From 1c60c731ba917f6af5b60265b3801b556ef2f178 Mon Sep 17 00:00:00 2001 From: tshenry Date: Wed, 4 Mar 2020 09:35:04 -0800 Subject: [PATCH 0077/1830] DEV: Mark `discourse-categories-suppressed` as official --- lib/plugin/metadata.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/plugin/metadata.rb b/lib/plugin/metadata.rb index 09826338c8..5ceabfde79 100644 --- a/lib/plugin/metadata.rb +++ b/lib/plugin/metadata.rb @@ -21,6 +21,7 @@ class Plugin::Metadata "discourse-cakeday", "discourse-canned-replies", "discourse-calendar", + "discourse-categories-suppressed", "discourse-characters-required", "discourse-chat-integration", "discourse-checklist", From 0e3e32f06cf9e4d9df7410c1cddb699e201612ce Mon Sep 17 00:00:00 2001 From: Kris Date: Wed, 4 Mar 2020 13:50:48 -0500 Subject: [PATCH 0078/1830] Remove some legacy tiger-striping css --- app/assets/stylesheets/mobile/topic-list.scss | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/assets/stylesheets/mobile/topic-list.scss b/app/assets/stylesheets/mobile/topic-list.scss index 5b6de216e5..516c864c04 100644 --- a/app/assets/stylesheets/mobile/topic-list.scss +++ b/app/assets/stylesheets/mobile/topic-list.scss @@ -345,15 +345,6 @@ tr.category-topic-link { } } - .topic-list > tbody > tr { - &:nth-child(odd) { - background-color: $secondary; - } - &:nth-child(even) { - background-color: $secondary; - } - } - th .badge-category { margin: 0; } From 6afeb91a4db7aa3a3288f1715aa66fed6026b416 Mon Sep 17 00:00:00 2001 From: Kris Date: Wed, 4 Mar 2020 14:48:22 -0500 Subject: [PATCH 0079/1830] UX: Input adjustments for category setting modal (tags tab) --- app/assets/stylesheets/common/base/modal.scss | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index e24acf027f..a294453181 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -457,6 +457,32 @@ } } +.edit-category-tab-tags { + .select-kit { + &.tag-chooser { + width: 100%; + + .select-kit-filter, + .filter-input { + display: flex; + flex: 1 0 250px; + } + + .mobile-view & { + .no-content, + .is-loading, + &.select-kit.is-expanded .select-kit-collection { + width: 95%; + } + } + } + } +} + +#category-min-tags-from-group { + min-height: 36px; +} + .incoming-email-modal { .btn { transition: none; From 3610709b6cf859f674a02394f1430bb51f68d117 Mon Sep 17 00:00:00 2001 From: Kris Date: Wed, 4 Mar 2020 16:53:32 -0500 Subject: [PATCH 0080/1830] Add classes for second-factor preferences --- .../discourse/templates/preferences-second-factor.hbs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/preferences-second-factor.hbs b/app/assets/javascripts/discourse/templates/preferences-second-factor.hbs index 5b0da4457e..fd8f57c54c 100644 --- a/app/assets/javascripts/discourse/templates/preferences-second-factor.hbs +++ b/app/assets/javascripts/discourse/templates/preferences-second-factor.hbs @@ -27,7 +27,7 @@ {{/if}} {{#if loaded}} -
+

{{i18n "user.second_factor.totp.title"}}

{{d-button action=(action "createTotp") @@ -54,7 +54,7 @@
-
+

{{i18n "user.second_factor.security_key.title"}}

{{d-button action=(action "createSecurityKey") @@ -81,7 +81,7 @@
-
+

{{i18n "user.second_factor_backup.title"}}

{{#if model.second_factor_enabled}} From a157f4aaaa8315e83d5be79e12aa630f11524c20 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Wed, 4 Mar 2020 15:38:27 +0530 Subject: [PATCH 0081/1830] Remove invite_admin route. --- app/controllers/admin/users_controller.rb | 35 ---------------- config/routes.rb | 1 - spec/requests/admin/users_controller_spec.rb | 44 -------------------- 3 files changed, 80 deletions(-) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 932de723b6..7ced962b3d 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -458,41 +458,6 @@ class Admin::UsersController < Admin::AdminController render json: { total: AdminUserIndexQuery.new(params).count_users } end - def invite_admin - raise Discourse::InvalidAccess.new unless is_api? - - email = params[:email] - unless user = User.find_by_email(email) - name = params[:name] if params[:name].present? - username = params[:username] if params[:username].present? - - user = User.new(email: email) - user.password = SecureRandom.hex - user.username = UserNameSuggester.suggest(username || name || email) - user.name = User.suggest_name(name || username || email) - end - - user.active = true - user.save! - user.grant_admin! - user.change_trust_level!(4) - user.email_tokens.update_all confirmed: true - - email_token = user.email_tokens.create(email: user.email) - - unless params[:send_email] == '0' || params[:send_email] == 'false' - Jobs.enqueue(:critical_user_email, - type: :account_created, - user_id: user.id, - email_token: email_token.token) - end - - render json: success_json.merge!( - password_url: "#{Discourse.base_url}#{password_reset_token_path(token: email_token.token)}" - ) - - end - def anonymize guardian.ensure_can_anonymize_user!(@user) if user = UserAnonymizer.new(@user, current_user).make_anonymous diff --git a/config/routes.rb b/config/routes.rb index 5d61ccc630..8fd2d19727 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -140,7 +140,6 @@ Discourse::Application.routes.draw do get 'users/:id/:username/tl3_requirements' => 'users#show' post "users/sync_sso" => "users#sync_sso", constraints: AdminConstraint.new - post "users/invite_admin" => "users#invite_admin", constraints: AdminConstraint.new resources :impersonate, constraints: AdminConstraint.new diff --git a/spec/requests/admin/users_controller_spec.rb b/spec/requests/admin/users_controller_spec.rb index 49a730ef64..92b79ce27f 100644 --- a/spec/requests/admin/users_controller_spec.rb +++ b/spec/requests/admin/users_controller_spec.rb @@ -757,50 +757,6 @@ RSpec.describe Admin::UsersController do end end - describe '#invite_admin' do - let(:api_key) { Fabricate(:api_key, user: admin) } - let(:api_params) do - { api_key: api_key.key, api_username: admin.username } - end - - it "doesn't work when not via API" do - post "/admin/users/invite_admin.json", params: { - name: 'Bill', username: 'bill22', email: 'bill@bill.com' - } - - expect(response.status).to eq(403) - end - - it 'should invite admin' do - expect do - post "/admin/users/invite_admin.json", params: api_params.merge( - name: 'Bill', username: 'bill22', email: 'bill@bill.com' - ) - end.to change { Jobs::CriticalUserEmail.jobs.size }.by(1) - - expect(response.status).to eq(200) - - u = User.find_by_email('bill@bill.com') - expect(u.name).to eq("Bill") - expect(u.username).to eq("bill22") - expect(u.admin).to eq(true) - expect(u.active).to eq(true) - expect(u.approved).to eq(true) - end - - it "doesn't send the email with send_email falsey" do - expect do - post "/admin/users/invite_admin.json", params: api_params.merge( - name: 'Bill', username: 'bill22', email: 'bill@bill.com', send_email: '0' - ) - end.to change { Jobs::CriticalUserEmail.jobs.size }.by(0) - - expect(response.status).to eq(200) - json = ::JSON.parse(response.body) - expect(json["password_url"]).to be_present - end - end - describe '#sync_sso' do let(:sso) { SingleSignOn.new } let(:sso_secret) { "sso secret" } From 83e649d08e0581a8e7c2ea3e69607e71b3912de0 Mon Sep 17 00:00:00 2001 From: Daniel Waterworth Date: Wed, 4 Mar 2020 17:28:26 +0000 Subject: [PATCH 0082/1830] FIX: Clobbering plugin files on startup is problematic On startup, (including when starting a rails console) we manipule a collection of plugin files. Writing these files is done in multiple observable steps, which presents opportunities for race conditions and causes temporary corruption. This commit uses the write, fsync and rename trick to atomically overwrite these files instead, but reads them first to avoid unnecessary writes. c457d3bf was a previous attempt to fix the same problem. --- lib/discourse.rb | 33 +++++++++++++++++++++++++++++++++ lib/plugin/instance.rb | 16 +++++++++------- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/lib/discourse.rb b/lib/discourse.rb index 57e8778e90..7241dc1c35 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -45,6 +45,39 @@ module Discourse logs.join("\n".freeze) end + def self.atomic_write_file(destination, contents) + begin + return if File.read(destination) == contents + rescue Errno::ENOENT + end + + FileUtils.mkdir_p(File.join(Rails.root, 'tmp')) + temp_destination = File.join(Rails.root, 'tmp', SecureRandom.hex) + + File.open(temp_destination, "w") do |fd| + fd.write(contents) + fd.fsync() + end + + File.rename(temp_destination, destination) + + nil + end + + def self.atomic_ln_s(source, destination) + begin + return if File.readlink(destination) == source + rescue Errno::ENOENT, Errno::EINVAL + end + + FileUtils.mkdir_p(File.join(Rails.root, 'tmp')) + temp_destination = File.join(Rails.root, 'tmp', SecureRandom.hex) + execute_command('ln', '-s', source, temp_destination) + File.rename(temp_destination, destination) + + nil + end + private class CommandRunner diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index b810a9dd78..eb7c2322fc 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -543,12 +543,11 @@ class Plugin::Instance Discourse::Utils.execute_command('mkdir', '-p', target) target << name.gsub(/\s/, "_") - # TODO a cleaner way of registering and unregistering - Discourse::Utils.execute_command('rm', '-f', target) - Discourse::Utils.execute_command('ln', '-s', public_data, target) + + Discourse::Utils.atomic_ln_s(public_data, target) end - ensure_directory(Plugin::Instance.js_path) + ensure_directory(js_file_path) contents = [] handlebars_includes.each { |hb| contents << "require_asset('#{hb}')" } @@ -558,12 +557,15 @@ class Plugin::Instance contents << (is_dir ? "depend_on('#{f}')" : "require_asset('#{f}')") end - File.delete(js_file_path) if js_asset_exists? - if contents.present? contents.insert(0, "<%") contents << "%>" - write_asset(js_file_path, contents.join("\n")) + Discourse::Utils.atomic_write_file(js_file_path, contents.join("\n")) + else + begin + File.delete(js_file_path) + rescue Errno::ENOENT + end end end From d953c908d2c6bbb8009f6a7895b74ad3f4a54d02 Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Thu, 5 Mar 2020 18:28:18 +0530 Subject: [PATCH 0083/1830] FEATURE: add child theme components in theme metadata. Now theme creators can add an array of child theme components in about.json file for a top level theme. --- app/models/remote_theme.rb | 2 ++ app/models/theme.rb | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/app/models/remote_theme.rb b/app/models/remote_theme.rb index e278da0ddb..24336ee4ff 100644 --- a/app/models/remote_theme.rb +++ b/app/models/remote_theme.rb @@ -40,6 +40,7 @@ class RemoteTheme < ActiveRecord::Base theme ||= Theme.new(user_id: user&.id || -1, name: theme_info["name"]) theme.component = theme_info["component"].to_s == "true" + theme.child_components = theme_info["components"].presence || [] remote_theme = new remote_theme.theme = theme @@ -63,6 +64,7 @@ class RemoteTheme < ActiveRecord::Base theme_info = RemoteTheme.extract_theme_info(importer) component = [true, "true"].include?(theme_info["component"]) theme = Theme.new(user_id: user&.id || -1, name: theme_info["name"], component: component) + theme.child_components = theme_info["components"].presence || [] remote_theme = new theme.remote_theme = remote_theme diff --git a/app/models/theme.rb b/app/models/theme.rb index 6a3b7a5643..cce0005a60 100644 --- a/app/models/theme.rb +++ b/app/models/theme.rb @@ -2,6 +2,8 @@ class Theme < ActiveRecord::Base + attr_accessor :child_components + @cache = DistributedCache.new('theme') belongs_to :user @@ -61,6 +63,17 @@ class Theme < ActiveRecord::Base notify_theme_change(with_scheme: notify_with_scheme) end + after_create do + if !component? && child_components.present? + child_components.each do |url| + url = ThemeStore::GitImporter.new(url.strip).url + theme = RemoteTheme.find_by(remote_url: url)&.theme + theme ||= RemoteTheme.import_theme(url, user) + child_themes << theme + end + end + end + def update_javascript_cache! all_extra_js = theme_fields.where(target_id: Theme.targets[:extra_js]).pluck(:value_baked).join("\n") if all_extra_js.present? From 79ce7085c25ff661d4c29c71de9dae2374c2dfc2 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 4 Mar 2020 11:10:23 -0500 Subject: [PATCH 0084/1830] SECURITY: Ensure the invite JSON API matches the UX Anonymous users could query the invite json and see counts and summaries which is not allowed in the UX of Discourse. This commit has those endpoints return a 403 unless the user is allowed to invite. --- app/controllers/users_controller.rb | 4 ++ spec/requests/users_controller_spec.rb | 61 ++++++++++++++++++++------ 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4fd276da5b..3da6474c22 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -274,6 +274,8 @@ class UsersController < ApplicationController end def invited + guardian.ensure_can_invite_to_forum! + inviter = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts)) offset = params[:offset].to_i || 0 filter_by = params[:filter] @@ -290,6 +292,8 @@ class UsersController < ApplicationController end def invited_count + guardian.ensure_can_invite_to_forum! + inviter = fetch_user_from_params(include_inactive: current_user.try(:staff?) || (current_user && SiteSetting.show_inactive_accounts)) pending_count = Invite.find_pending_invites_count(inviter) diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index a452f4e897..18727eeca6 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -1429,16 +1429,47 @@ describe UsersController do end end - describe '#invited' do - it 'returns success' do + describe "#invited_count" do + it "fails for anonymous users" do user = Fabricate(:user) + get "/u/#{user.username}/invited_count.json" + expect(response.status).to eq(403) + end + + it "works for users who can see invites" do + inviter = Fabricate(:user, trust_level: 2) + sign_in(inviter) + invitee = Fabricate(:user) + invite = Fabricate(:invite, invited_by: inviter, user: invitee) + get "/u/#{user.username}/invited_count.json" + expect(response.status).to eq(200) + + json = JSON.parse(response.body) + expect(json).to be_present + expect(json['counts']).to be_present + end + end + + describe '#invited' do + it 'fails for anonymous users' do + user = Fabricate(:user) + get "/u/#{user.username}/invited.json", params: { username: user.username } + + expect(response.status).to eq(403) + end + + it 'returns success' do + user = Fabricate(:user, trust_level: 2) + sign_in(user) get "/u/#{user.username}/invited.json", params: { username: user.username } expect(response.status).to eq(200) end it 'filters by email' do - inviter = Fabricate(:user) + inviter = Fabricate(:user, trust_level: 2) + sign_in(inviter) + invitee = Fabricate(:user) Fabricate( :invite, @@ -1454,6 +1485,7 @@ describe UsersController do ) get "/u/#{inviter.username}/invited.json", params: { search: 'billybob' } + expect(response.status).to eq(200) invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) @@ -1461,7 +1493,9 @@ describe UsersController do end it 'filters by username' do - inviter = Fabricate(:user) + inviter = Fabricate(:user, trust_level: 2) + sign_in(inviter) + invitee = Fabricate(:user, username: 'billybob') _invite = Fabricate( :invite, @@ -1476,6 +1510,7 @@ describe UsersController do ) get "/u/#{inviter.username}/invited.json", params: { search: 'billybob' } + expect(response.status).to eq(200) invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) @@ -1489,19 +1524,19 @@ describe UsersController do Fabricate(:invite, invited_by: inviter) get "/u/#{user.username}/invited/pending.json" - - invites = JSON.parse(response.body)['invites'] - expect(invites).to be_empty + expect(response.status).to eq(403) end end context 'with redeemed invites' do it 'returns invites' do - inviter = Fabricate(:user) + inviter = Fabricate(:user, trust_level: 2) + sign_in(inviter) invitee = Fabricate(:user) invite = Fabricate(:invite, invited_by: inviter, user: invitee) get "/u/#{inviter.username}/invited.json" + expect(response.status).to eq(200) invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) @@ -1514,11 +1549,12 @@ describe UsersController do context 'with pending invites' do context 'with permission to see pending invites' do it 'returns invites' do - inviter = Fabricate(:user) + inviter = Fabricate(:user, trust_level: 2) invite = Fabricate(:invite, invited_by: inviter) sign_in(inviter) get "/u/#{inviter.username}/invited/pending.json" + expect(response.status).to eq(200) invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) @@ -1538,21 +1574,20 @@ describe UsersController do end get "/u/#{inviter.username}/invited/pending.json" - - json = JSON.parse(response.body)['invites'] - expect(json).to be_empty + expect(response.status).to eq(403) end end end context 'with redeemed invites' do it 'returns invites' do - _user = sign_in(Fabricate(:user)) + sign_in(Fabricate(:user, trust_level: 2)) inviter = Fabricate(:user) invitee = Fabricate(:user) invite = Fabricate(:invite, invited_by: inviter, user: invitee) get "/u/#{inviter.username}/invited.json" + expect(response.status).to eq(200) invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) From e01d5e2adcc46e0161b297d19d516e0722b7d2ff Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 4 Mar 2020 11:47:09 -0500 Subject: [PATCH 0085/1830] SECURITY: Add more restrictions on invite emails They could be filtered and returned in some circumstances where they shouldn't have been. --- app/controllers/users_controller.rb | 9 +++- app/serializers/invite_serializer.rb | 2 +- lib/guardian.rb | 4 ++ spec/requests/users_controller_spec.rb | 68 +++++++++++++++----------- 4 files changed, 51 insertions(+), 32 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 3da6474c22..e96a79c953 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -286,8 +286,13 @@ class UsersController < ApplicationController Invite.find_redeemed_invites_from(inviter, offset) end - invites = invites.filter_by(params[:search]) - render_json_dump invites: serialize_data(invites.to_a, InviteSerializer), + show_emails = guardian.can_see_invite_emails?(inviter) + if params[:search].present? + filter_sql = '(LOWER(users.username) LIKE :filter)' + filter_sql = '(LOWER(invites.email) LIKE :filter) or (LOWER(users.username) LIKE :filter)' if show_emails + invites = invites.where(filter_sql, filter: "%#{params[:search].downcase}%") + end + render_json_dump invites: serialize_data(invites.to_a, InviteSerializer, show_emails: show_emails), can_see_invite_details: guardian.can_see_invite_details?(inviter) end diff --git a/app/serializers/invite_serializer.rb b/app/serializers/invite_serializer.rb index befa52fc21..9c03c813fb 100644 --- a/app/serializers/invite_serializer.rb +++ b/app/serializers/invite_serializer.rb @@ -5,7 +5,7 @@ class InviteSerializer < ApplicationSerializer attributes :email, :updated_at, :redeemed_at, :expired, :user def include_email? - !object.redeemed? + options[:show_emails] && !object.redeemed? end def expired diff --git a/lib/guardian.rb b/lib/guardian.rb index 080faf78a9..fae144f2b6 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -331,6 +331,10 @@ class Guardian is_me?(user) end + def can_see_invite_emails?(user) + is_staff? || is_me?(user) + end + def can_invite_to_forum?(groups = nil) authenticated? && (SiteSetting.max_invites_per_day.to_i > 0 || is_staff?) && diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 18727eeca6..ed28cab650 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -1466,23 +1466,13 @@ describe UsersController do expect(response.status).to eq(200) end - it 'filters by email' do + it 'filters by all if viewing self' do inviter = Fabricate(:user, trust_level: 2) sign_in(inviter) invitee = Fabricate(:user) - Fabricate( - :invite, - email: 'billybob@example.com', - invited_by: inviter, - user: invitee - ) - Fabricate( - :invite, - email: 'jimtom@example.com', - invited_by: inviter, - user: invitee - ) + Fabricate(:invite, email: 'billybob@example.com', invited_by: inviter, user: invitee) + Fabricate(:invite, email: 'jimtom@example.com', invited_by: inviter, user: invitee) get "/u/#{inviter.username}/invited.json", params: { search: 'billybob' } expect(response.status).to eq(200) @@ -1490,31 +1480,51 @@ describe UsersController do invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) expect(invites.first).to include('email' => 'billybob@example.com') + + get "/u/#{inviter.username}/invited.json", params: { search: invitee.username } + expect(response.status).to eq(200) + + invites = JSON.parse(response.body)['invites'] + expect(invites.size).to eq(2) + expect(invites[0]['email']).to be_present end - it 'filters by username' do + it "doesn't filter by email if another regular user" do inviter = Fabricate(:user, trust_level: 2) - sign_in(inviter) + sign_in(Fabricate(:user, trust_level: 2)) - invitee = Fabricate(:user, username: 'billybob') - _invite = Fabricate( - :invite, - invited_by: inviter, - email: 'billybob@example.com', - user: invitee - ) - Fabricate( - :invite, - invited_by: inviter, - user: Fabricate(:user, username: 'jimtom') - ) + invitee = Fabricate(:user) + Fabricate(:invite, email: 'billybob@example.com', invited_by: inviter, user: invitee) + Fabricate(:invite, email: 'jimtom@example.com', invited_by: inviter, user: invitee) + + get "/u/#{inviter.username}/invited.json", params: { search: 'billybob' } + expect(response.status).to eq(200) + + invites = JSON.parse(response.body)['invites'] + expect(invites.size).to eq(0) + + get "/u/#{inviter.username}/invited.json", params: { search: invitee.username } + expect(response.status).to eq(200) + + invites = JSON.parse(response.body)['invites'] + expect(invites.size).to eq(2) + expect(invites[0]['email']).to be_blank + end + + it "filters by email if staff" do + inviter = Fabricate(:user, trust_level: 2) + sign_in(Fabricate(:moderator)) + + invitee = Fabricate(:user) + Fabricate(:invite, email: 'billybob@example.com', invited_by: inviter, user: invitee) + Fabricate(:invite, email: 'jimtom@example.com', invited_by: inviter, user: invitee) get "/u/#{inviter.username}/invited.json", params: { search: 'billybob' } expect(response.status).to eq(200) invites = JSON.parse(response.body)['invites'] expect(invites.size).to eq(1) - expect(invites.first).to include('email' => 'billybob@example.com') + expect(invites[0]['email']).to be_present end context 'with guest' do @@ -1581,7 +1591,7 @@ describe UsersController do context 'with redeemed invites' do it 'returns invites' do - sign_in(Fabricate(:user, trust_level: 2)) + sign_in(Fabricate(:moderator)) inviter = Fabricate(:user) invitee = Fabricate(:user) invite = Fabricate(:invite, invited_by: inviter, user: invitee) From 4b70719a484b2b4bbc6ed3ce526e293d6e18b59a Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 5 Mar 2020 12:45:42 -0500 Subject: [PATCH 0086/1830] Update translations --- config/locales/client.bg.yml | 70 +++++++++ config/locales/client.bs_BA.yml | 120 ++++++++++++++- config/locales/client.ca.yml | 4 +- config/locales/client.da.yml | 1 + config/locales/client.de.yml | 21 ++- config/locales/client.es.yml | 8 +- config/locales/client.fa_IR.yml | 47 ++++++ config/locales/client.fi.yml | 4 +- config/locales/client.fr.yml | 4 +- config/locales/client.he.yml | 142 +++++++++--------- config/locales/client.it.yml | 52 +++++-- config/locales/client.nl.yml | 10 +- config/locales/client.pl_PL.yml | 3 - config/locales/client.pt_BR.yml | 4 +- config/locales/client.ru.yml | 24 +-- config/locales/client.sl.yml | 1 + config/locales/client.sv.yml | 19 ++- config/locales/client.tr_TR.yml | 4 +- config/locales/client.uk.yml | 4 +- config/locales/client.ur.yml | 4 +- config/locales/client.vi.yml | 10 +- config/locales/client.zh_CN.yml | 4 +- config/locales/server.ar.yml | 1 - config/locales/server.be.yml | 2 - config/locales/server.bg.yml | 16 +- config/locales/server.bs_BA.yml | 18 ++- config/locales/server.ca.yml | 2 - config/locales/server.de.yml | 14 +- config/locales/server.el.yml | 2 - config/locales/server.es.yml | 4 +- config/locales/server.fa_IR.yml | 11 +- config/locales/server.fi.yml | 2 - config/locales/server.fr.yml | 2 - config/locales/server.he.yml | 3 +- config/locales/server.hy.yml | 2 - config/locales/server.it.yml | 20 ++- config/locales/server.ja.yml | 1 - config/locales/server.ko.yml | 2 - config/locales/server.nl.yml | 1 + config/locales/server.pl_PL.yml | 2 - config/locales/server.pt.yml | 1 - config/locales/server.pt_BR.yml | 2 - config/locales/server.ro.yml | 1 - config/locales/server.ru.yml | 2 - config/locales/server.sk.yml | 1 - config/locales/server.sq.yml | 1 - config/locales/server.sr.yml | 1 - config/locales/server.sv.yml | 1 + config/locales/server.tr_TR.yml | 2 - config/locales/server.uk.yml | 2 - config/locales/server.ur.yml | 2 - config/locales/server.vi.yml | 1 - config/locales/server.zh_CN.yml | 8 +- config/locales/server.zh_TW.yml | 2 - .../config/locales/client.bs_BA.yml | 20 +++ .../config/locales/client.fa_IR.yml | 1 + .../config/locales/server.bs_BA.yml | 28 ++++ .../config/locales/server.nl.yml | 23 +++ plugins/poll/config/locales/client.bs_BA.yml | 38 ++++- plugins/poll/config/locales/server.bs_BA.yml | 8 + 60 files changed, 614 insertions(+), 196 deletions(-) diff --git a/config/locales/client.bg.yml b/config/locales/client.bg.yml index ddcd6759e6..9dd640fb5b 100644 --- a/config/locales/client.bg.yml +++ b/config/locales/client.bg.yml @@ -148,6 +148,9 @@ bg: visible: enabled: "добавена в списъка %{when}" disabled: "премахната от списъка %{when}" + forwarded: "препрати горния имейл" + topic_admin_menu: "действия по темата" + wizard_required: "Добре дошли във вашия нов Discourse! Нека започнем с съветника за настройка ✨" emails_are_disabled: "Всички изходящи имейли са изцяло забранени от администратора. Няма да бъдат изпращани никакви имейл известия." bootstrap_mode_enabled: "За да помогнем със стартирането на вашия нов сайт по-лесно поставихме сайта в \"стартиращо режим\". Всички нови потребители ще получат ниво на доверие 1 и ще имат активирани дневни известия за активноста във форума. Този режим ще бъде автоматично спрян когато бройката регистрирани потребители стигне %{min_users} ." themes: @@ -256,8 +259,17 @@ bg: not_bookmarked: "добавете тази публикация в Отметки" remove: "Премахнете отметката" save: "Запази" + reminders: + later_today: "По-късно днес
{{date}}" + next_business_day: "Следващият работен ден
{{date}}" + tomorrow: "Утре
{{date}}" + next_week: "Следващата седмица
{{date}}" + next_month: "Следващият месец
{{date}}" drafts: + resume: "Продължи" remove: "Премахване" + new_topic: "Проект на нова тема" + topic_reply: "Проект на отговор" abandon: yes_value: "Да, напусни" no_value: "Не, запази" @@ -287,38 +299,89 @@ bg: edit: "Редактирай този банер >>" choose_topic: none_found: "Няма нови теми." + title: + search: "Търсене на тема" + choose_message: + none_found: "Не са намерени съобщения." + title: + search: "Търси съобщения" review: order_by: "Подреди по" + in_reply_to: "в отговор на" explain: + formula: "Формула" total: "Общо" + awaiting_approval: "Очаква одобрение" delete: "Изтрий" settings: save_changes: "Запази промените" title: "Настройки" + view_all: "Виж всички" + grouped_by_topic: "Групирани по тема" + title: "Преглед" topic: "Тема:" filtered_user: "Потребител" + show_all_topics: "покажи всички теми" user: + bio: "Биография" + website: "Уебсайт" username: "Потребителско име" email: "Имейл" name: "Име" + fields: "Полета" + user_percentage: + agreed: + one: "{{count}}% са съгласни" + other: "{{count}}% са съгласни" + disagreed: + one: "{{count}}% не са съгласни" + other: "{{count}}% не са съгласни" + ignored: + one: "{{count}}% игнорира" + other: "{{count}}% са без отношение" topics: topic: "Тема" + reviewable_count: "Брой" + details: "детайли" + unique_users: + one: "%{count} потребител" + other: "{{count}} потребители" + replies: + one: "%{count} отговор" + other: "{{count}} отговора" edit: "Редактирай" save: "Запази" cancel: "Отмени" filters: + all_categories: "(всички категории)" type: title: "Тип" + all: "(всички видове)" refresh: "Опресни" + status: "Статус" category: "Категория" + orders: + priority: "Приоритет" + priority_asc: "Приоритет (по обратен ред)" + created_at: "Създадено на" + created_at_asc: "Създадено на (по обратен ред)" + priority: + medium: "Среден" + high: "Висок" scores: + score: "Точки" date: "Дата" type: "Тип" + status: "Статус" statuses: pending: title: "Чакащи" + approved: + title: "Одобрена" rejected: title: "Отхвърлени" + deleted: + title: "Изтрита" types: reviewable_user: title: "Потребител" @@ -434,6 +497,11 @@ bg: members: title: "Членове" filter_placeholder: "Потребителско име" + remove_member: "Премахни Потребител" + remove_member_description: "Премахни %{username} от тази група" + make_owner: "Направи Собственик" + remove_owner: "Премахни като Собственик" + remove_owner_description: "Премахни %{username} като собственик на тази група" owner: "Собественик" topics: "Теми" posts: "Публикации" @@ -519,6 +587,7 @@ bg: topics_entered: "добавени теми" post_count: "# публикации" confirm_delete_other_accounts: "Сигурни ли сте, че искате да изтриете тези профили?" + copied: "копирано" user_fields: none: "(изберете опция)" user: @@ -1679,6 +1748,7 @@ bg: search_priority: options: normal: "Нормален" + high: "Висок" sort_options: likes: "Харесвания" views: "Преглеждания" diff --git a/config/locales/client.bs_BA.yml b/config/locales/client.bs_BA.yml index dec41a729a..99061a6922 100644 --- a/config/locales/client.bs_BA.yml +++ b/config/locales/client.bs_BA.yml @@ -174,6 +174,8 @@ bs_BA: banner: enabled: "postavi kao zastavicu %{when}. Pojavljivat će se na vrhu svake stranice sve dok je korisnik ne zatvori." disabled: "odkloni zastavicu %{when}.Neće se više prikazivati na vrhu svake stranice." + forwarded: "gornji email proslijeđen" + topic_admin_menu: "akcije u vezi teme" wizard_required: "Dobrodošli na vaš novi Discourse! Odpočnimo sa čarobnjakom za postavke ✨" emails_are_disabled: "Sve odlazeće email poruke su globalno onemogućene od strane administratora. Ni jedna notifikacija bilo koje vrste neće biti poslana." bootstrap_mode_enabled: "Kako bi olakšali lansiranje vaše nove web stranice, trenutačno ste u \"bootstrap\" načinu rada. Svim novim korisnicima će se dodjeljivati nivo povjerenja 1 i imati uključen dnevni izvještaj dešavanja na forumu preko email-a. Ovo će se automatski isključiti nakon što %{min_users} korisnika prijavi račun na forumu." @@ -285,9 +287,19 @@ bs_BA: bookmarks: created: "zabilježili ste ovu stranicu" not_bookmarked: "sačuvaj ovaj post" + created_with_reminder: "postavili ste zabilješku na ovu objavu s podsjetnikom %{date}" remove: "Ukloni zabilješku" confirm_clear: "Dali ste sigurni dali želite izbrisati sve sačuvane stvari iz ove teme?" save: "Sačuvaj" + no_timezone: 'Još uvijek niste postavili vremensku zonu, tako da nećete biti u mogućnosti koristiti podsjetnike. Postavite vremensku zonu na vašem profilu.' + reminders: + at_desktop: "Sljedeći put sam za svojim desktop kompjuterom" + later_today: "Danas, malo kasnije
{{date}}" + next_business_day: "Sljedeći radni dan
{{date}}" + tomorrow: "Sutradan
{{date}}" + next_week: "Sljedeće sedmice
{{date}}" + next_month: "Sljedeći mjesec
{{date}}" + custom: "Precizno vrijeme i datum" drafts: resume: "Nastavi" remove: "Ukloni" @@ -332,13 +344,41 @@ bs_BA: banner: close: "Odkaži ovu zastavicu." edit: "Uredite ovu zastavicu >>" + pwa: + install_banner: "Da li želite instalirati %{title} na ovaj uređaj?" choose_topic: none_found: "Nema tema." + title: + search: "Traži Temu" + placeholder: "ovdje ukucajte naslov teme, url ili id" choose_message: none_found: "nisam našao nijednu poruku" + title: + search: "Traži poruku" + placeholder: "ovdje ukucajte naslov poruke, url ili id" review: order_by: "Pordeak po" in_reply_to: "odgovori na" + explain: + why: "objasnite zašto je ovaj objekat završio na listi za čekanje" + title: "Ocjenjiv Skor" + formula: "Formula" + subtotal: "Podsuma" + total: "Suma" + min_score_visibility: "Minimalni skor za Vidljivost" + score_to_hide: "Skor za Skrivanje objave" + take_action_bonus: + name: "preduzeo akciju" + title: "Kada član uprave odluči da poduzme akciju, zastavici je dodijeljen bonus." + user_accuracy_bonus: + name: "korisnička preciznost" + title: "Korisnicima čije su zastave prethodno bivale usaglašene dobivaju bonus." + trust_level_bonus: + name: "nivo povjerenja" + title: "Ocjenjivi objekti kreirani od strane korisnika sa višim nivoom povjerenja imaju viši skor." + type_bonus: + name: "bonus tip" + title: "Neki ocjenjivi tipovi mogu zaprimiti bonus od strane osoblja foruma kako bi tim tipovima podigli prioritet" claim_help: optional: "Možete tražiti ova da sprijećite ostale da ga pregledaju" required: "VI morate tvrditi stavari prije ih morate cijeniti" @@ -373,6 +413,8 @@ bs_BA: deleted_post: "(post izbrisan)" deleted_user: "(korisnik izbrisan)" user: + bio: "Biografija" + website: "Web stranica" username: "Ime" email: "Email" name: "Ime" @@ -572,6 +614,8 @@ bs_BA: leave: "Napusti" request: "Zatraži" message: "Poruka" + confirm_leave: "Jeste li sigurni da želite napustiti ovu grupu?" + allow_membership_requests: "Dopusti korisnicima da smiju slati molbe za učlanjenje u grupu vlasnicima grupa (Potrebno je da je grupa javno vidljiva)" membership_request_template: "Prilagođeni memorandum kao priložak koji se prikazuje korisnicima prilikom slanja zahtjeva za učlanjenje" membership_request: submit: "Poslati zahtjev " @@ -619,6 +663,7 @@ bs_BA: remove_owner: "Ukloni kao vlasnika" remove_owner_description: "Ukloni %{username} kao vlasnika ove grupe" owner: "Vlasnik" + forbidden: "Nije vam dozvoljeno da vidite članove." topics: "Teme" posts: "Postovi" mentions: "Spomenuto" @@ -753,14 +798,19 @@ bs_BA: activity_stream: "Aktivnost" preferences: "Postavke" feature_topic_on_profile: + open_search: "Odaberi Novu temu" + title: "Odaberi temu" + search_label: "Traži temu po naslovu" save: "Sačuvaj" clear: title: "Clear" + warning: "Jeste li sigurni da želite vašu istaknutu temu očistiti?" profile_hidden: "Javni profil ovog korisnika je skriven" expand_profile: "Proširi" collapse_profile: "Spusti" bookmarks: "Zabilješke" bio: "O Meni" + timezone: "Vremenska zona" invited_by: "Pozvan od" trust_level: "Nivo povjerenja" notifications: "Obaviještenja" @@ -787,6 +837,7 @@ bs_BA: enable_quoting: "Uključi \"citiran odgovor\" za označen tekst" enable_defer: "Omogući odlaganje za označavanje tema nepročitanih" change: "promjeni" + featured_topic: "Istaknuta tema" moderator: "{{user}} je moderator" admin: "{{user}} je admin" moderator_tooltip: "Ovaj korisnik je moderator" @@ -894,6 +945,7 @@ bs_BA: copied_to_clipboard: "Kopirano u međuspremnik" copy_to_clipboard_error: "Pogreška pri kopiranju podataka u međuspremnik" remaining_codes: "Imate preostale rezervne kodove {{count}} ." + use: "Koristi backup kod" enable_prerequisites: "Morate omogućiti primarni drugi faktor prije generiranja rezervnih kodova." codes: title: "Generirani sigurnosni kodovi" @@ -901,6 +953,7 @@ bs_BA: second_factor: title: "Two Factor Authentication" enable: "Upravljanje autentifikacijom sa dva faktora" + forgot_password: "Zaboravili ste password?" confirm_password_description: "Molimo vas da potvrdite šifru kako bi nastavili" name: "Ime" label: "Šifra" @@ -914,6 +967,7 @@ bs_BA: extended_description: | Dvofaktorna autentifikacija dodaje dodatnu sigurnost vašem računu tako što zahtijeva dodatnu jednokratnu oznaku pored vaše lozinke. Tokeni se mogu generirati na Android i iOS uređajima. oauth_enabled_warning: "Imajte na umu da će ulogovanje korištenjem socijalnih mreža biti isključeno u momentu kad uključite two factor authentication (dvofaktorsku ovjeru autentičnosti) na vašem korisničkom računu." + use: "Koristi Authenticator app?" enforced_notice: "Morate omogućiti autentifikaciju s dva faktora prije pristupa ovoj web-lokaciji." disable: "onemogući" disable_title: "Onemogući Drugi Faktor" @@ -921,11 +975,20 @@ bs_BA: edit: "Izmijeni" edit_title: "Uredi drugi faktor" edit_description: "Ime drugog faktora" + enable_security_key_description: "Kada ste pripremili vaš fizikalni sigurnosni ključ (physical security key), pritisnite ispod dugme Registriraj." totp: title: "Autentikatori zasnovani na tokenu" add: "Novi Authenticator" default_name: "Moj Authenticator" security_key: + register: "Registriraj" + title: "Sigurnosni ključevi" + add: "Registriraj sigurnosni ključ" + default_name: "Glavni sigurnosni ključ" + not_allowed_error: "Proces registracije sigurnosnog ključa je ili vremenski istekao ili je odkazan." + already_added_error: "Već ste registrovali ovaj sigurnosni ključ. Nemate potrebe da ga ponovo registrujete." + edit: "Izmijeni sigurnosni ključ" + edit_description: "Ime sigurnosnog ključa" delete: "Izbriši" change_about: title: "Promjeni O meni" @@ -952,9 +1015,15 @@ bs_BA: uploaded_avatar_empty: "Dodajte vašu sliku" upload_title: "Učitajte vašu sliku sa uređaja" image_is_not_a_square: "Upozorenje: morali smo izrezat vašu sliku; nije bila kvadratnog oblika." + change_profile_background: + title: "Profil zaglavlja" + instructions: "Profili zaglavlja će biti centrirani i imati standardno širinu od 1110 piksela." change_card_background: title: "Pozadina Korisničke kartice" instructions: "Pozadinske slike će biti centrirane i imati standard širinu od 590 pixela." + change_featured_topic: + title: "Istaknuta tema" + instructions: "Link na ovu temu će biti prikazan na vašoj korisničkoj kartici i profilu." email: title: "Email" primary: "Primarni Email" @@ -979,6 +1048,7 @@ bs_BA: confirm_modal_title: "Povezani %{provider} račun" confirm_description: account_specific: "Vaš %{provider} račun %{account_description} će biti korišten za autentifikaciju." + generic: "Vaš %{provider} račun će biti korišten za prijavu." name: title: "Ime" instructions: "vaše puno ime (opciono)" @@ -1090,6 +1160,7 @@ bs_BA: search: "kucaj da potražiš pozivnice..." title: "Pozivnice" user: "Pozvan korisnik" + sent: "Zadnje poslano" none: "Nema pozivnica za prikazati" truncated: one: "Prikaz prve pozivnice." @@ -1307,6 +1378,8 @@ bs_BA: reset: "Resetuj Šifru" complete_username: "Ako se vaš nalog podudara sa korisnikom %{username}, uskoro ćete primiti email koji će vam objasniti kako da resetujete vašu šifru." complete_email: "Ako se vaš nalog podudara sa %{email}, uskoro ćete primiti email koji će vam objasniti kako da resetujete vašu šifru." + complete_username_found: "Pronašli smo račun koji se podudara sa korisničkim imenom %{username}. Trebali bi uskoro dobiti email sa instrukcijama kako da resetujete vaš password." + complete_email_found: "Pronašli smo račun koji se podudara sa %{email}. Trebali bi uskoro dobiti email sa instrukcijama kako da resetujete vaš password." complete_username_not_found: "Nema naloga sa korisničkim imenom %{username}" complete_email_not_found: "Nema naloga sa email-om %{email}" help: "Email još ne stiže? Prvo provjerite vaš spam folder u email pregledniku.

Niste sigurni koji email ste koristili? Unesite email adresu i mi ćemo vas obavjestiti da li ista postoji kod nas.

Ukoliko nemate više pristup vašoj email kojom ste registrovali korisnički račun, molimo vas da se obratite našim administratorima za pomoć.

" @@ -1330,8 +1403,15 @@ bs_BA: password: "Šifra" second_factor_title: "Two Factor Authentication" second_factor_description: "Molimo da unesete kod za ovjeru autentičnosti sa vaše aplikacije:" + second_factor_backup: "Loguj se koristeći backup kod" second_factor_backup_title: "rezevna zaštita za dva faktora" second_factor_backup_description: "Molim ukucajte jedan od vaši rezevni kodova" + second_factor: "Loguj se koristeći Authenticator app" + security_key_description: "Kada ste pripremili vaš fizikalni sigurnosni ključ (physical security key), pritisnite ispod dugme Prijava pomoću sigurnosnog ključa." + security_key_alternative: "Pokušaj na drugi način" + security_key_authenticate: "Prijava pomoću sigurnosnog ključa" + security_key_not_allowed_error: "Ovaj proces prijave pomoću sigurnosnog ključa je ili vremenski istekao ili je odkazan." + security_key_no_matching_credential_error: "Nisu pronađeni korisnički podatci koristeći navedeni sigurnosni ključ." email_placeholder: "email ili korisnik" caps_lock_warning: "Uključena su vam velika slova" error: "Nepoznata greška" @@ -1426,6 +1506,7 @@ bs_BA: one: "Označi bar {{count}} predmet." few: "Označi bar {{count}} predmeta." other: "Označi bar {{count}} predmeta." + invalid_selection_length: "Označeno mora biti najmanje {{count}} karaktera dugo." date_time_picker: from: Od to: Ka @@ -1486,10 +1567,12 @@ bs_BA: title_missing: "Naslov je obavezan" title_too_short: "Naslov mora biti najmanje {{min}} karaktera" title_too_long: "Naslov ne može biti više od {{max}} karaktera" + post_missing: "Objava ne može biti prazna" post_length: "Odgovor mora biti najmanje {{min}} karaktera" try_like: "Dail ste pokušali{{heart}}dugme?" category_missing: "Morate odabrati kategoriju" tags_missing: "Morate odabrati najmanje {{count}} oznaka" + topic_template_not_modified: "Molimo da dodate detalje i specifikacije za vašu temu tako što ćete izmijeniti template teme." save_edit: "Sačuvaj izmjene" overwrite_edit: "Overwrite Edit" reply_original: "Odgovori na Originalnu temu" @@ -1514,6 +1597,7 @@ bs_BA: view_new_post: "Pogledaj svoj novi post." saving: "Spašavam" saved: "Sačuvano!" + saved_draft: "Sastav je u toku. Tipkajte kako bi nastavili dalje." uploading: "Uplodujem..." show_preview: "pokaži pregled »" hide_preview: "« sakri pregled" @@ -2247,7 +2331,7 @@ bs_BA: attachment_download_requires_login: "Sorry, you need to be logged in to download attachments." abandon_edit: no_value: "Ne, sačuvaj" - no_save_draft: "Ne,spasi skicu" + no_save_draft: "Ne, spasi sastav" abandon: confirm: "Da li ste sigurni da želite otkazati vaš post?" no_value: "Ne, sačuvaj" @@ -2574,6 +2658,7 @@ bs_BA: help: "Ovu temu sajt ne lista među najnovijim temama. Neće biti prisutna ni među listama tema unutar kategorija. Jedini način da se dođe do ove teme je direktan link" personal_message: title: "Ova tema je lična poruka" + help: "Ova tema je lična poruka" posts: "Odgovori" posts_long: "postoji {{number}} odgovora u ovoj temi" posts_likes_MF: | @@ -2729,6 +2814,7 @@ bs_BA: title: "Aplikacija" create: "%{shortcut} Započni novu temu" notifications: "%{shortcut} Otvori notifikacije" + hamburger_menu: "%{shortcut} Otvori padajući meni" user_profile_menu: "%{shortcut} Otvori meni korisnika" show_incoming_updated_topics: "%{shortcut} Pročitaj promjenje teme" search: "%{shortcut} Traži" @@ -2761,6 +2847,7 @@ bs_BA: mark_watching: "%{shortcut} Motri temu" print: "%{shortcut} Odštampaj temu" defer: "%{shortcut} Defer temu" + topic_admin_actions: "%{shortcut} Otvori opcije administriranja teme" badges: earned_n_times: one: "Zaradio / la sam ovu oznaku %{count} time" @@ -2805,13 +2892,39 @@ bs_BA: changed: "oznake promijenjene:" tags: "Oznake" choose_for_topic: "izborne oznake" + info: "Informacija" + default_info: "Ovaj oznaka nije predodređena ni za jednu kategoriju i nema sinonime." + category_restricted: "Ova oznaka je predodređena za kategorije na koje nemate pravo pristupa." + synonyms: "Sinonimi" + synonyms_description: "U slučaju da se sljedeće oznake koriste, iste će biti zamijenjene sa %{base_tag_name}." + tag_groups_info: + one: 'Ovaj tag pripada grupi "{{tag_groups}}".' + few: "Ovaj tag pripada sljedećim grupama: {{tag_groups}}." + other: "Ova oznaka pripada sljedećim grupama: {{tag_groups}}." + category_restrictions: + one: "Moguće je koristiti samo u sljedećoj kategoriji:" + few: "Moguće je koristiti samo u sljedećim kategorijama:" + other: "Moguće je koristiti samo u sljedećim kategorijama:" + edit_synonyms: "Uredi sinonime" + add_synonyms_label: "Dodaj sinonime:" add_synonyms: "Dodaj" + add_synonyms_explanation: + one: "Svaka lokacija koja trenutno koristi ovu oznaku bit će zamjenjena sa %{tag_name}. Jeste li sigurni da želite izvršiti tu promjenu?" + few: "Svaka lokacija koja trenutno koristi ove oznake bit će zamjenjena sa %{tag_name}. Jeste li sigurni da želite izvršiti tu promjenu?" + other: "Svaka lokacija koja trenutno koristi ove oznake bit će zamjenjena sa %{tag_name}. Jeste li sigurni da želite izvršiti tu promjenu?" + add_synonyms_failed: "Sljedeće oznake nije moguće dodati kao sinonime: %{tag_names}. Osigurajte prvo da nemaju već postojeće sinonime i da nisu sinonimi neke druge oznake." + remove_synonym: "Odstrani sinonim" + delete_synonym_confirm: 'Jeste li sigurni da želite izbrisati sinonim "%{tag_name}"?' delete_tag: "Izbriši oznaku" delete_confirm: one: "Jeste li sigurni da želite izbrisati ovu oznaku i ukloniti je iz teme %{count} kojoj je dodijeljen?" few: "Jeste li sigurni da želite izbrisati ovu oznaku i ukloniti je iz tema {{count}} kojima je dodijeljena?" other: "Jeste li sigurni da želite izbrisati ovu oznaku i ukloniti je iz tema {{count}} kojima je dodijeljena?" delete_confirm_no_topics: "Jeste li sigurni da želite izbrisati ovu oznaku?" + delete_confirm_synonyms: + one: "Pripadajući sinonim će također biti obrisan." + few: "Pripadajućih {{count}} sinonima će također biti obrisano." + other: "Pripadajućih {{count}} sinonima će također biti obrisano." rename_tag: "Promjeni ime Oznake" rename_instructions: "Odaberite novo ime za oznaku:" sort_by: "Sortiraj po:" @@ -2854,6 +2967,7 @@ bs_BA: description: "You will be notified only if someone mentions your @name or replies to your post." muted: title: "Utišan" + description: "Nećete bit obavješteni bilo čime o ovoj temi sa ovom oznakom, i neće se pojavljivati na tabularu nepročitanih tema." groups: title: "Označite grupe" about: "Dodajte oznake grupama da biste ih lakše upravljali." @@ -2865,6 +2979,7 @@ bs_BA: parent_tag_description: "Oznake iz ove grupe ne mogu se koristiti ako roditeljska oznaka nije prisutna." one_per_topic_label: "Ograničite jednu oznaku po temi iz ove grupe" new_name: "Nova Grupa Oznaka" + name_placeholder: "Ime grupe oznaka" save: "Sačuvaj" delete: "Delete" confirm_delete: "Jeste li sigurni da želite izbrisati ovu grupu oznaka?" @@ -4123,11 +4238,14 @@ bs_BA: filter: "Pretraga (URL ili vanjski URL)" reseed: modal: + title: "Zamijeni tekst" categories: "Kategorije" topics: "Teme" + replace: "Zamijeni" wizard_js: wizard: done: "Urađeno" + finish: "Završi" back: "Prethodno" next: "Iduće" step: "%{current} od %{total}" diff --git a/config/locales/client.ca.yml b/config/locales/client.ca.yml index 0f69a6d177..74b0aab013 100644 --- a/config/locales/client.ca.yml +++ b/config/locales/client.ca.yml @@ -1230,9 +1230,6 @@ ca: enabled: "El lloc web és en mode només de lectura. Continueu navegant, però de moment estan desactivades les accions de respondre, 'm'agrada' i altres." login_disabled: "S'ha desactivat l'inici de sessió mentre aquest lloc web es trobi en mode només de lectura." logout_disabled: "S'ha desactivat el tancament de sessió mentre aquest lloc web es trobi en mode només de lectura." - too_few_topics_and_posts_notice: "Comencem la discussió! Hi ha %{currentTopics} temes i %{currentPosts} publicacions. Els visitants en necessiten més per a llegir i respondre. Recomanem almenys %{requiredTopics} temes i %{requiredPosts} publicacions. Sols l'equip responsable pot veure aquest missatge." - too_few_topics_notice: "Comencem la discussió! Hi ha %{currentTopics} / temes. Els visitants en necessiten més per a llegir i respondre. Recomanem almenys %{requiredTopics} temes. Sols l'equip responsable pot veure aquest missatge." - too_few_posts_notice: "Comencem la discussió! Hi ha %{currentPosts} publicacions. Els visitants en necessiten més per a llegir i respondre. Recomanem almenys %{requiredPosts} publicacions. Sols l'equip responsable pot veure aquest missatge." logs_error_rate_notice: reached_hour_MF: "{relativeAge} - {rate, plural, one {# error/hora} other {# errors/hora} s'ha arribat al límit de configuració del lloc web de {limit, plural, one {# error/hora} other {# errors/hora}}." reached_minute_MF: "{relativeAge} - {rate, plural, one {# error/minut} other {# errors/minut}} s'ha arribat al límit de configuració del lloc web de {limit, plural, one {# error/minut} other {# errors/minut}}." @@ -2562,6 +2559,7 @@ ca: help: "Aquest tema no és visible; no es mostrarà en la llista de temes i només és accessible amb un enllaç directe." personal_message: title: "Aquest tema és un missatge personal" + help: "Aquest tema és un missatge personal" posts: "Publicacions" posts_long: "hi ha {{number}} publicacions a aquest tema" posts_likes_MF: | diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index 8af7ff9135..87ac724689 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -2539,6 +2539,7 @@ da: help: "Dette emne er ulistet; det vil ikke blive vist i listen over emner og kan kun tilgås med et direkte link" personal_message: title: "Dette emne er en privat besked" + help: "Dette emne er en privat besked" posts: "Indlæg" posts_long: "{{number}} indlæg i dette emne" posts_likes_MF: | diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index 66f021b825..d39417f661 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -153,6 +153,7 @@ de: banner: enabled: "hat dieses Banner erstellt, %{when}. Es wird oberhalb jeder Seite angezeigt, bis es vom Benutzer weggeklickt wird." disabled: "hat dieses Banner entfernt, %{when}. Es wird nicht mehr oberhalb jeder Seite angezeigt." + forwarded: "hat die obige E-Mail weitergeleitet" topic_admin_menu: "Themen Aktionen" wizard_required: "Willkommen bei deinem neuen Discourse! Lass uns mit dem Setup-Assistenten ✨ starten" emails_are_disabled: "Die ausgehende E-Mail-Kommunikation wurde von einem Administrator global deaktiviert. Es werden keinerlei Benachrichtigungen per E-Mail verschickt." @@ -579,6 +580,7 @@ de: request: "Anfrage" message: "Nachricht" confirm_leave: "Willst du die Gruppe wirklich verlassen?" + allow_membership_requests: "Erlaube Benutzern, Mitgliedschaftsanfragen an Gruppenbesitzer zu senden (erfordert, öffentlich sichtbare Gruppen)" membership_request_template: "Benutzerdefinierte Vorlage, das Benutzern angezeigt wird, die eine Mitgliedschaftsanfrage senden" membership_request: submit: "Anfrage abschicken" @@ -1259,9 +1261,8 @@ de: enabled: "Diese Website befindet sich im Nur-Lesen-Modus. Du kannst weiterhin Inhalte lesen, aber das Erstellen von Beiträgen, Vergeben von Likes und Durchführen einiger weiterer Aktionen ist derzeit nicht möglich." login_disabled: "Die Anmeldung ist deaktiviert während sich die Website im Nur-Lesen-Modus befindet." logout_disabled: "Die Abmeldung ist deaktiviert während sich die Website im Nur-Lesen-Modus befindet." - too_few_topics_and_posts_notice: "Lass die Diskussion beginnen! Es gibt %{currentTopics} Themen und %{currentPosts} Beiträge. Besucher brauchen mehr zum Lesen und Beantworten – wir empfehlen mindestens %{requiredTopics} Themen und %{requiredPosts} Beiträge. Diese Nachricht ist nur für das Team sichtbar." - too_few_topics_notice: "Lass die Diskussion beginnen! Es gibt %{currentTopics} Themen. Besucher brauchen mehr zum Lesen und Beantworten – wir empfehlen mindestens %{requiredTopics} Themen. Diese Nachricht ist nur für das Team sichtbar." - too_few_posts_notice: "Lass die Diskussion beginnen! Es gibt %{currentPosts} Beiträge. Besucher brauchen mehr zum Lesen und Beantworten – wir empfehlen mindestens %{requiredPosts} Beiträge. Diese Nachricht ist nur für das Team sichtbar." + too_few_topics_and_posts_notice_MF: >- + Lass' die Diskussion beginnen! Es {currentTopics, plural, one {ist # Thema} other {sind # Themen}} und {currentPosts, plural, one {# Beitrag} other {# Beiträge}} vorhanden. Besucher brauchen mehr zum Lesen und Beantworten – wir empfehlen mindestens {requiredTopics, plural, one {# Thema} other {# Themen}} und {requiredPosts, plural, one {# Beitrag} other {# Beiträge}}. Dieser Hinweis wird nur Teammitgliedern gezeigt. logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# Fehler/Stunde} other {# errors/hour}} hat die Grenze der Webseiten-Einstellung von {limit, plural, one {# Fehler/Stunde} other {# Fehler/Stunde}} erreicht." reached_minute_MF: "{relativeAge}{rate, plural, one {# Fehler/Minute} other {# Fehler/Minute}} hat die Grenze der Webseiten-Einstellung von {limit, plural, one {# Fehler/Minute} other {# Fehler/Minute}} erreicht." @@ -1332,6 +1333,8 @@ de: reset: "Passwort zurücksetzen" complete_username: "Wenn ein Benutzerkonto dem Benutzernamen %{username} entspricht, solltest du in Kürze eine E-Mail mit Anweisungen zum Zurücksetzen deines Passwortes erhalten." complete_email: "Wenn ein Benutzerkonto der E-Mail %{email} entspricht, solltest du in Kürze eine E-Mail mit Anweisungen zum Zurücksetzen deines Passwortes erhalten." + complete_username_found: "Wir haben ein zum Benutzernamen %{username} gehörendes Konto gefunden. Du solltest in Kürze eine E-Mail mit Anweisungen zum Zurücksetzen deines Passwortes erhalten. " + complete_email_found: "Wir haben ein zu %{email} gehörendes Benutzerkonto gefunden. Du solltest in Kürze eine E-Mail mit Anweisungen zum Zurücksetzen deines Passwortes erhalten. " complete_username_not_found: "Es gibt kein Konto mit dem Benutzernamen %{username}" complete_email_not_found: "Es gibt kein Benutzerkonto für %{email}" help: "E-Mail nicht angekommen? Bitte prüfe zuerst deinen Spam-Ordner.

Nicht sicher, welche E-Mail-Adresse du verwendet hast? Gib eine E-Mail-Adresse ein und wir werden dir sagen, ob sie hier existiert.

Falls du keinen Zugriff mehr auf die hinterlegte E-Mail-Adresse deines Kontos hast, kontaktiere bitte unser hilfsbereites Team.

" @@ -1464,6 +1467,7 @@ de: min_content_not_reached: one: "Wähle mindestens einen Eintrag aus." other: "Wähle mindestens {{count}} Einträge aus." + invalid_selection_length: "Es müssen wenigstens{{count}} Zeichen markiert sein." date_time_picker: from: Von to: An @@ -1553,6 +1557,7 @@ de: view_new_post: "Sieh deinen neuen Beitrag an." saving: "Wird gespeichert" saved: "Gespeichert!" + saved_draft: "Beitrags-Entwurf vorhanden. Tippen, um fortzusetzen." uploading: "Wird hochgeladen…" show_preview: "Vorschau anzeigen »" hide_preview: "« Vorschau ausblenden" @@ -1602,6 +1607,7 @@ de: reply_as_new_topic: label: Antworte als verknüpftes Thema desc: "Erstelle ein neues Thema, das auf dieses Thema verweist" + confirm: "Du hast einen neuen Themen-Entwurf gespeichert. Wenn du ein verlinktes Thema erstellst, wird er überschrieben." reply_as_private_message: label: Neue Nachricht desc: Erstelle eine neue Nachricht @@ -2414,6 +2420,10 @@ de: name: "Name" name_placeholder: "Gib dem Lesezeichen einen Namen, um dein Gedächtnis zu unterstützen" set_reminder: "Erstelle eine Erinnerung" + actions: + delete_bookmark: + name: "Lesezeichen löschen" + description: "Entfernt das Lesezeichen von deinem Profil und beendet alle Erinnerungen für dieses Lesezeichen" category: can: "kann… " none: "(keine Kategorie)" @@ -2615,6 +2625,7 @@ de: help: "Dieses Thema ist unsichtbar. Es wird in keiner Themenliste angezeigt und kann nur mit einem direkten Link betrachtet werden." personal_message: title: "Dieses Thema ist eine persönliche Nachricht" + help: "Dieses Thema ist eine persönliche Nachricht" posts: "Beiträge" posts_long: "dieses Thema enthält {{number}} Beiträge" posts_likes_MF: | @@ -2834,6 +2845,7 @@ de: choose_for_topic: "optionale Schlagwörter" info: "Info" default_info: "Dieses Schlagwort ist nicht auf Kategorien beschränkt und hat keine Synonyme." + category_restricted: "Dieser Tag ist auf Kategorien begrenzt, für die du keine Zugriffsberechtigung hast." synonyms: "Synonyme" synonyms_description: "Wenn die folgenden Schlagwörter verwendet werden, werden sie durch %{base_tag_name} ersetzt." tag_groups_info: @@ -4202,7 +4214,8 @@ de: description: Das gleiche Abzeichen vielen Benutzern auf einmal verleihen. no_badge_selected: "Bitte wähle ein Abzeichen, um anzufangen." perform: "Verleihe Abzeichen an Benutzer" - success: Deine CSV Datei wurde empfangen und die Benutzer werden ihr Abzeichen in Kürzle bekommen. + upload_csv: Lade eine CSV-Datei mit entweder den E-Mail Adressen oder den Benutzernamen hoch + success: Deine CSV Datei wurde empfangen und die Benutzer werden ihr Abzeichen in Kürze bekommen. replace_owners: Entferne das Abzeichen von vorherigen Eigentümern emoji: title: "Emoji" diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index 78d165658c..f103b397ae 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -1261,9 +1261,6 @@ es: enabled: "Este sitio está en modo de solo lectura. Puedes continuar navegando pero algunas acciones como responder o dar me gusta no están disponibles por ahora." login_disabled: "Iniciar sesión está desactivado mientras el foro se encuentre en modo de solo lectura." logout_disabled: "Cerrar sesión está desactivado mientras el sitio se encuentre en modo de solo lectura." - too_few_topics_and_posts_notice: "¡Comencemos la discusión! Hay %{currentTopics} temas y %{currentPosts} publicaciones. Los visitantes necesitan más cosas para leer y responder. Recomendamos al menos %{requiredTopics} temas y %{requiredPosts} publicaciones. Solo el staff puede ver este mensaje." - too_few_topics_notice: "¡Comencemos la discusión! Hay %{currentTopics} temas. Los visitantes necesitan más cosas para leer y responder. Recomendamos al menos %{requiredTopics} temas. Solo el staff puede ver este mensaje." - too_few_posts_notice: "¡Comencemos la discusión! Hay %{currentPosts} publicaciones. Los visitantes necesitan más cosas para leer y responder. Recomendamos al menos %{requiredPosts} publicaciones. Solo el staff puede ver este mensaje." logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} otros {# errors/hour}} alcanzó el límite de la configuración del sitio de {limit, plural, one {# error/hour} otros {# errors/hour}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} otros {# errors/minute}} alcanzó el límite de la configuración del sitio de {limit, plural, one {# error/minute} otros {# errors/minute}}." @@ -2626,6 +2623,7 @@ es: help: "Este tema es invisible. No se mostrará en la lista de temas y solo se le puede acceder mediante un enlace directo" personal_message: title: "Este tema es un mensaje personal" + help: "Este tema es un mensaje personal" posts: "Publicaciones" posts_long: "Hay {{number}} publicaciones en este tema" posts_likes_MF: | @@ -4218,8 +4216,8 @@ es: description: Concede la misma medalla a muchos usuarios a la vez. no_badge_selected: "Por favor, selecciona una medalla para empezar." perform: "Conceder medalla a los usuarios" - upload_csv: Sube un archivo CSV con correos electrónicos o nombres de usuario. - aborted: Sube un archivo CSV que contenga correos electrónicos o nombres de usuario. + upload_csv: Sube un archivo CSV con correos electrónicos o nombres de usuario + aborted: "Por favor, sube un archivo CSV que contenga correos electrónicos o nombres de usuario" success: Se recibió el CSV y los usuarios recibirán la medalla dentro de poco. replace_owners: Quitar medalla de los anteriores portadores emoji: diff --git a/config/locales/client.fa_IR.yml b/config/locales/client.fa_IR.yml index 50bbf323e2..2cae3f58ea 100644 --- a/config/locales/client.fa_IR.yml +++ b/config/locales/client.fa_IR.yml @@ -27,6 +27,7 @@ fa_IR: millions: "{{number}} میلیون" dates: time: "h:mm a" + time_short_day: "h:mm a" timeline_date: "MMM YYYY" long_no_year: "MMM D h:mm a" long_no_year_no_time: "MMM D" @@ -152,6 +153,8 @@ fa_IR: banner: enabled: "این در %{when} یک بنر شد، تا زمانی که کاربر آن را ببندد بالای صفحه خواهد ماند." disabled: "این بنر در %{when} حذف شده. و دیگر در بالای صفحات نمایش داده نمی‌شود." + forwarded: "ایمیل بالا را ارسال کرد" + topic_admin_menu: "اقدامات موضوع" wizard_required: "به دیسکورس خوش آمدید! برای شروع نصب کلیک کنید ✨" emails_are_disabled: "تمام ایمیل های خروجی بصورت کلی توسط مدیر قطع شده است. هیچگونه ایمیل اگاه سازی ارسال نخواهد شد." bootstrap_mode_enabled: "برای راه‌اندازی راحت‌تر سایت جدید، حالت خود‌راه‌انداز فعال شده. به تمام کاربران سطح اعتماد 1 اعطا می‌شود و ایمیل خلاصه روزانه به صورت پیشفرض برای ایشان فعال می‌شود. این امکان بصورت خودکار وقتی تعداد کاربران از %{min_users} بیشتر شود، غیر فعال خواهد شد." @@ -261,9 +264,19 @@ fa_IR: bookmarks: created: "شما این نوشته را نشانک زده‌اید" not_bookmarked: "این نوشته را نشانک بزنید" + created_with_reminder: "شما بر روی این پست نشانک همراه با یادآوری گذاشته اید در %{date}" remove: "پاک کردن نشانک" confirm_clear: "آیا مطمئنید می‌خواهید همه‌ی نشانک‌های خود را از این موضوع پاک کنید؟" save: "ذخیره" + no_timezone: 'شما هنوز منطقه زمانی مشخص نکرده اید. شما قادر به تنظیم کردن یادآوری نیستید. یکی را در پروفایل تان تنظیم کنید.' + reminders: + at_desktop: "بار آینده من پشت میزم هستم" + later_today: "امروز کمی بعد
{{date}}" + next_business_day: "روز کاری آینده
{{date}}" + tomorrow: "فردا
{{date}}" + next_week: "هفته ی آینده
{{date}}" + next_month: "ماه آینده
{{date}}" + custom: "درج تاریخ و ساعت" drafts: resume: "از سر گیری" remove: "پاک کردن" @@ -309,19 +322,37 @@ fa_IR: install_banner: "ایامایل هستید تا ، %{title} را بر‌روی دستگاه شما نصب کند؟" choose_topic: none_found: "موضوعی یافت نشد." + title: + search: "جستجوی یک موضوع" + placeholder: "جستجوی بر اساس عنوان، لینک و یا آیدی" choose_message: none_found: "پیامی پیدا نشد" + title: + search: "جستجو برای یک پیام" + placeholder: "عنوان پیام، لینک و یا آیدی آن را اینجا وارد کنید" review: order_by: "به ترتیب" in_reply_to: "در پاسخ به" explain: why: "توضیح دهید که چرا این مورد در صف پایان یافت" + title: "امتیازدهی قابل تجدید نظر" formula: "فرمول" + subtotal: "جمع جزء" total: "مجموع" + min_score_visibility: "حداقل امتیاز برای دیده شدن" + score_to_hide: "امتیاز برای پنهان کردن پست" + take_action_bonus: + name: "اقدام كرد" + title: "زمانی که یکی از کارمندان انتخاب می کند که اقدام کند، پرچم یک امتیاز می دهد." user_accuracy_bonus: name: "دقت کاربر" + title: "کاربرانی که پرچم آن ها به طور گروهی پذیرفته شده است، یک امتیاز دریافت می کنند." trust_level_bonus: name: "سطح اعتماد" + title: "موارد قابل بررسی که توسط کاربرانی با میزان اعتماد بیشتر ایجاد شده اند، اولویت بالاتری دارند." + type_bonus: + name: "امتیاز را وارد کنید" + title: "موارد قابل بررسی خاص می توانند کارمندان دارای امتیاز شوند تا اولویت آن ها را بیشتر کند." claim_help: optional: "می‌توانید این مورد را درخواست کنید تا دیگران را از بازنگری آن بازنگه دارید." required: "شما قبل از بازنگری موارد باید آن‌ها را درخواست دهید ." @@ -355,6 +386,8 @@ fa_IR: deleted_post: "(نوشته حذف شده)" deleted_user: "(کاربر حذف شده)" user: + bio: "بیوگرافی" + website: "وبسایت" username: "نام‌کاربری" email: "ایمیل" name: "نام" @@ -546,6 +579,8 @@ fa_IR: leave: "ترک کردن" request: "درخواست" message: "پیام" + confirm_leave: "آیا از ترک این گروه مطمئن هستید؟" + allow_membership_requests: "به کاربرها اجازه ی ارسال درخواست عضویت به صاحبان گروه را بدهید\n(گروه باید برای عموم قابل دیدن باشد)" membership_request_template: "الگوی سفارشی برای نمایش به کاربران هنگام ارسال درخواست عضویت" membership_request: submit: "ارسال درخواست" @@ -724,14 +759,19 @@ fa_IR: activity_stream: "فعالیت" preferences: "تنظیمات" feature_topic_on_profile: + open_search: "انتخاب یک موضوع نو" + title: "انتخاب یک موضوع" + search_label: "جستجوی یک موضوع بر اساس عنوان" save: "ذخیره" clear: title: "واضح" + warning: "آیا از پاکسازی موضوع برجسته ی خود مطمئن هستید؟" profile_hidden: "صفحه نمایه این کاربر مخفی است" expand_profile: "باز کردن" collapse_profile: "جمع کردن" bookmarks: "نشانک‌ها" bio: "درباره من" + timezone: "منطقه ی زمانی" invited_by: "دعوت شده توسط" trust_level: "سطح اعتماد" notifications: "آگاه‌سازی‌ها" @@ -758,6 +798,7 @@ fa_IR: enable_quoting: "فعال کردن نقل قول گرفتن از متن انتخاب شده" enable_defer: "تاخیر را برای علامت زدن مباحث به عنوان خوانده نشده فعال کن" change: "تغییر" + featured_topic: "مبحث برجسته" moderator: "{{user}} یک مدیر است" admin: "{{user}} یک مدیر ارشد است" moderator_tooltip: "این کاربر یک مدیر است" @@ -865,6 +906,7 @@ fa_IR: copied_to_clipboard: "کپی شد" copy_to_clipboard_error: "خطا در کپی اطلاعات" remaining_codes: "شما {{count}}کد پشتیبان باقی مانده دارید." + use: "از کد پشتیبان استفاده کنید" enable_prerequisites: "شما باید قبل از ساخت کد‌های پشتیبانی یک تایید هویت دوعاملی اصلی را فعال کنید " codes: title: "کد پشتیبان تولید شد" @@ -872,6 +914,7 @@ fa_IR: second_factor: title: "احراز هویت دو مرحله ای" enable: "مدیریت تایید هوییت دوعاملی" + forgot_password: "فراموشی گذرواژه؟" confirm_password_description: "لطفا رمز عبور خود را تایید کنید تا ادامه دهیم." name: "نام" label: "کد" @@ -885,6 +928,7 @@ fa_IR: extended_description: | احراز هویت دو عامله امنیت بیشتری به حساب کاربری شما میدهد، چرا که یک توکن یک بار مصرف علاوه بر رمز عبور خود خواهید داشت. توکن ها در ابزارهای اندروید و IOS قابل تولید هستند. oauth_enabled_warning: "دقت کنید وقتی احراز هویت دوعامله فعال شود، ورود با حساب شبکه های اجتماعی به حساب کاربری شما از کار میفتد." + use: "از اپلیکیشن احراز هویت استفاده کنید" enforced_notice: "شما باید احراز هویت دو عامله را قبل از دسترسی به سایت فعال کنید" disable: "غیرفعال" disable_title: "غیر فعال کردن تایید دوعاملی" @@ -933,6 +977,8 @@ fa_IR: change_card_background: title: "پس زمینه کارت کابر" instructions: "تصاویر پس زمینه در مرکز قرار خواهند گرفت و عرض پیشفرض آن 590 پیکسل است" + change_featured_topic: + title: "مبحث برجسته" email: title: "ایمیل" primary: "آدرس ایمیل اصلی" @@ -2475,6 +2521,7 @@ fa_IR: help: "این موضوع از فهرست خارج شد؛ و در فهرست موضوعات نمایش داده نخواهد شد، و فقط از طریق لینک مستقیم در دسترس خواهد بود. " personal_message: title: "این تاپیک یک پیام‌خصوصی است" + help: "این تاپیک یک پیام‌خصوصی است" posts: "نوشته‌ها" posts_long: "این موضوع {{number}} نوشته دارد" posts_likes_MF: | diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 2f9baea226..7b4b32cd72 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -1260,9 +1260,6 @@ fi: enabled: "Sivusto on vain luku -tilassa. Voit jatkaa selailua, mutta vastaaminen, tykkääminen ja muita toimintoja on toistaiseksi poissa käytöstä." login_disabled: "Et voi kirjautua sisään, kun sivusto on vain luku -tilassa." logout_disabled: "Et voi kirjautua ulos, kun sivusto on vain luku -tilassa." - too_few_topics_and_posts_notice: "Laitetaanpa keskustelu alulle! Tällä hetkellä palstalla on %{currentTopics} ketjua ja %{currentPosts} viestiä. Uusia kävijöitä varten tarvitaan lisää keskusteluita, joita voivat lukea ja joihin vastata. Suosittelemme vähintään %{requiredTopics} ketjua ja %{requiredPosts} viestiä. Vain henkilökunta näkee tämän viestin." - too_few_topics_notice: "Laitetaanpa keskustelu alulle! Tällä hetkellä palstalla on %{currentTopics} ketjua. Uusia kävijöitä varten tarvitaan lisää keskusteluita, joita voivat lukea ja joihin vastata. Suosittelemme vähintään %{requiredTopics} ketjua. Vain henkilökunta näkee tämän viestin." - too_few_posts_notice: "Laitetaanpa keskustelu alulle! Tällä hetkellä palstalla on %{currentPosts} viestiä. Uusia kävijöitä varten tarvitaan lisää keskusteluita, joita voivat lukea ja joihin vastata. Suosittelemme vähintään %{requiredPosts} viestiä. Vain henkilökunta näkee tämän viestin." logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# virhe/tunti} other {# virhettä/tunti}} saavutti sivustoasetuskynnyksen {limit, plural, one {# virhe/tunti} other {# virhettä/tunti}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# virhe/minuutti} other {# virhettä/minuutti}} saavutti sivustoasetuskynnyksen {limit, plural, one {# virhe/minuutti} other {# virhettä/minuutti}}." @@ -2625,6 +2622,7 @@ fi: help: "Tämä ketju on poistettu listauksista; sitä ei näytetä ketjulistauksissa vaan siihen pääsee vain suoran linkin kautta" personal_message: title: "Tämä ketju on yksityiskeskustelu" + help: "Tämä ketju on yksityiskeskustelu" posts: "Viestejä" posts_long: "tässä ketjussa on {{number}} viestiä" posts_likes_MF: | diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index 253b3c6321..a4f35a7890 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -1262,9 +1262,6 @@ fr: enabled: "Le site est en mode lecture seule. Vous pouvez continer à naviguer, mais les réponses, J'aime et autre interactions sont désactivées pour l'instant." login_disabled: "La connexion est désactivée quand le site est en lecture seule." logout_disabled: "La déconnexion est désactivée quand le site est en lecture seule." - too_few_topics_and_posts_notice: "Commençons la discussion! Il y a / %{currentTopics} sujets et %{currentPosts} messages. Les visiteurs ont besoin de plus à consulter et répondre – %{requiredTopics} sujets et %{requiredPosts} messages sont recommandés. Seul le personnel peut voir ce message." - too_few_topics_notice: "Commençons la discussion! Il y a / %{currentTopics} sujets. Les visiteurs ont besoin de plus à consulter et répondre – %{requiredTopics} sujets sont recommandés. Seul le personnel peut voir ce message." - too_few_posts_notice: "Commençons la discussion! Il y a / %{currentPosts} messages. Les visiteurs ont besoin de plus à consulter et répondre – %{requiredPosts} messages sont recommandés. Seul le personnel peut voir ce message." logs_error_rate_notice: reached_hour_MF: "{relativeAge} – {rate, plural, one {# erreur/heure} other {# erreurs/heure}} arrive à la limite paramétrée de {limit, plural, one {# erreur/heure} other {# erreurs/heure}}." reached_minute_MF: "{relativeAge} – {rate, plural, one {# erreur/minute} other {# erreurs/minute}} arrive à la limite paramétrée de {limit, plural, one {# erreur/minute} other {# erreurs/minute}}." @@ -2625,6 +2622,7 @@ fr: help: "Ce sujet n'apparait plus dans la liste des sujets et sera seulement accessible via un lien direct" personal_message: title: "Ce sujet est un message personnel" + help: "Ce sujet est un message personnel" posts: "Messages" posts_long: "il y a {{number}} messages dans ce sujet" posts_likes_MF: |2 diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index 852a7968bf..c6c9b2b68e 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -302,7 +302,7 @@ he: user_count: "משתמשים" active_user_count: "משתמשים פעילים" contact: "יצירת קשר" - contact_info: "במקרה של ארוע קריטי או דחוף המשפיע על האתר, נא ליצור אתנו קשר דרך: %{contact_info}." + contact_info: "במקרה של בעיה קריטית או דחופה המשפיעה על אתר זה, נא ליצור אתנו קשר דרך: %{contact_info}." bookmarked: title: "סימנייה" clear_bookmarks: "מחיקת סימניות" @@ -332,24 +332,24 @@ he: new_private_message: "טיוטת הודעה פרטית חדשה" topic_reply: "טיוטת תשובה" abandon: - confirm: "כבר קיימת טיוטה בנושא זה, האם את/ה בטוח/ה שאת/ה רוצה לזנוח אותה?" - yes_value: "כן, נטוש" + confirm: "כבר קיימת טיוטה בנושא זה. לנטוש אותה?" + yes_value: "כן, לנטוש" no_value: "לא, שמור" topic_count_latest: - one: "ראה נושא {{count}} חדש או מעודכן" - two: "ראה {{count}} נושאים חדשים או מעודכנים" - many: "ראה {{count}} נושאים חדשים או מעודכנים" - other: "ראה {{count}} נושאים חדשים או מעודכנים" + one: "הצגת נושא {{count}} חדש או עדכני" + two: "הצגת {{count}} נושאים חדשים או עדכניים" + many: "הצגת {{count}} נושאים חדשים או עדכניים" + other: "הצגת {{count}} נושאים חדשים או עדכניים" topic_count_unread: - one: "ראה נושא {{count}} שלא נקרא" - two: "ראה {{count}} נושאים שלא נקראו" - many: "ראה {{count}} נושאים שלא נקראו" - other: "ראה {{count}} נושאים שלא נקראו" + one: "הצגת נושא {{count}} שלא נקרא" + two: "הצגת {{count}} נושאים שלא נקראו" + many: "הצגת {{count}} נושאים שלא נקראו" + other: "הצגת {{count}} נושאים שלא נקראו" topic_count_new: - one: "ראה נושא {{count}} חדש" - two: "ראה {{count}} נושאים חדשים" - many: "ראה {{count}} נושאים חדשים" - other: "ראה {{count}} נושאים חדשים" + one: "הצגת נושא {{count}} חדש" + two: "הצגת {{count}} נושאים חדשים" + many: "הצגת {{count}} נושאים חדשים" + other: "הצגת {{count}} נושאים חדשים" preview: "תצוגה מקדימה" cancel: "ביטול" save: "שמירת השינויים" @@ -380,7 +380,7 @@ he: search: "חיפוש אחר נושא" placeholder: "נא להקליד כאן את כותרת הנושא, הכתובת או את המזהה" choose_message: - none_found: "לא נמצאו הודעות" + none_found: "לא נמצאו הודעות." title: search: "חיפוש אחר הודעה" placeholder: "נא להקליד כאן את כותרת ההודעה, הכתובת או את המזהה" @@ -486,7 +486,7 @@ he: two: "{{count}} תגובות" many: "{{count}} תגובות" other: "{{count}} תגובות" - edit: "ערוך" + edit: "עריכה" save: "שמירה" cancel: "ביטול" new_topic: "אישור הפריט הזה ייצור נושא חדש" @@ -512,7 +512,7 @@ he: conversation: view_full: "הצגת הדיון המלא" scores: - about: "ניקוד זה מחושב בהתאם למידת האמון של המדווח, הדיוק בדיגולים הקודמים ועדיפות הפריט המדווח." + about: "ניקוד זה מחושב בהתאם לדרגת האמון של המדווח, הדיוק בסימונים הקודמים ועדיפות הפריט המדווח." score: "ניקוד" date: "תאריך" type: "סוג" @@ -600,7 +600,7 @@ he: member_added: "הוסיף" member_requested: "בקשה התקבלה ב־" add_members: - title: "הוסף חברים" + title: "הוספת חברים" description: "נהל את החברות של קבוצה זו" usernames: "שמות משתמשים" requests: @@ -612,11 +612,11 @@ he: denied: "נדחה" undone: "הבקשה נמשכה" manage: - title: "נהל" + title: "ניהול" name: "שם" full_name: "שם מלא" - add_members: "הוסף חברים" - delete_member_confirm: "להסיר את '%{username}' מהקבוצה '%{group}'?" + add_members: "הוספת חברים" + delete_member_confirm: "להסיר את ‚%{username}’ מהקבוצה ‚%{group}’?" profile: title: פרופיל interaction: @@ -655,7 +655,7 @@ he: allow_membership_requests: " לאפשר למשתמשים לשלוח בקשות חברות לבעלי הקבוצה (נדרשת קבוצה גלויה לכלל)" membership_request_template: "תבנית מותאמת אישית שתוצג למשתמשים בעת שליחת בקשת חברות" membership_request: - submit: "שלח בקשה" + submit: "הגשת בקשה" title: "בקש להצטרף ל%{group_name}" reason: "תן לבעלי הקבוצה לדעת למה אתה שייך לקבוצה זו" membership: "חברות" @@ -811,13 +811,13 @@ he: user: said: "{{username}}:" profile: "פרופיל" - mute: "השתק" + mute: "השתקה" edit: "עריכת העדפות" download_archive: button_text: "להוריד הכל" confirm: "להוריד את הפוסטים שלך?" - success: "הורדה החלה, תקבלו הודעה כאשר התהליך הסתיים." - rate_limit_error: "ניתן להוריד פוסטים פעם ביום, אנא נסו שוב מחר." + success: "ההורדה החלה, תישלח אליך הודעה עם סיום התהליך." + rate_limit_error: "ניתן להוריד פוסטים פעם אחת ביום, נא לנסות שוב מחר." new_private_message: "הודעה חדשה" private_message: "הודעה" private_messages: "הודעות" @@ -844,7 +844,7 @@ he: search_label: "חיפוש אחר נושא לפי כותרת" save: "שמירה" clear: - title: "נקה" + title: "ניקוי" warning: "למחוק את הנושאים המומלצים שלך?" profile_hidden: "הפרופיל הציבורי של משתמש זה מוסתר" expand_profile: "הרחב" @@ -874,7 +874,7 @@ he: theme_default_on_all_devices: "הגדרת ערכת עיצוב זו כבררת המחדל לכל המכשירים שלי" text_size_default_on_all_devices: "הפוך את גודל הטקסט הזה לברירת המחדל בכל המכשירים שלי" allow_private_messages: "אפשר למשתמשים אחרים לשלוח לי הודעות פרטיות" - external_links_in_new_tab: "פתח את כל הקישורים החיצוניים בעמוד חדש" + external_links_in_new_tab: "פתיחת כל הקישורים החיצוניים בלשונית חדשה" enable_quoting: "הפעלת תגובת ציטוט לטקסט מסומן" enable_defer: "הפעלת דחייה לאחר כך כדי לסמן נושאים כלא נקראו" change: "שנה" @@ -887,7 +887,7 @@ he: suspended_notice: "המשתמש הזה מושעה עד לתאריך: {{date}}." suspended_permanently: "משתמש זה מושעה." suspended_reason: "הסיבה: " - github_profile: "גיטהאב" + github_profile: "GitHub" email_activity_summary: "סיכום פעילות" mailing_list_mode: label: "מצב רשימת תפוצה" @@ -919,12 +919,12 @@ he: muted_categories_instructions: "לא תקבל הודעה בנוגע לנושאים חדשים בקטגוריות אלה, והם לא יופיעו בקטגוריות או בדפים האחרונים." muted_categories_instructions_dont_hide: "לא תישלחנה אליך התראות על שום דבר בנוגע לנושאים בקטגוריות האלו." no_category_access: "בתור פיקוח יש לך גישה מוגבלת לקטגוריות, שמירה מנוטרלת." - delete_account: "מחק את החשבון שלי" + delete_account: "מחיקת החשבון שלי" delete_account_confirm: "להסיר את החשבון? לא ניתן לבטל פעולה זו!" - deleted_yourself: "חשבונך נמחק בהצלחה." - delete_yourself_not_allowed: "נא לפנות לחבר סגל אם ברצונך למחוק את חשבונך." + deleted_yourself: "החשבון שלך נמחק בהצלחה." + delete_yourself_not_allowed: "נא לפנות לחבר סגל אם ברצונך למחוק את החשבון שלך." unread_message_count: "הודעות" - admin_delete: "מחק" + admin_delete: "מחיקה" users: "משתמשים" muted_users: "מושתק" muted_users_instructions: "להשבית כל התראה ממשתמשים אלו" @@ -953,10 +953,10 @@ he: archive: "ארכיון" groups: "הקבוצות שלי" bulk_select: "בחר הודעות" - move_to_inbox: "העבר לדואר נכנס" + move_to_inbox: "העברה לדואר נכנס" move_to_archive: "ארכיון" failed_to_move: "בעיה בהעברת ההודעות שנבחרו (אולי יש תקלה בהתחברות?)" - select_all: "בחרו הכל" + select_all: "לבחור הכול" tags: "תגיות" preferences_nav: account: "חשבון" @@ -1013,7 +1013,7 @@ he: disable: "נטרול" disable_title: "נטרול אימות דו־שלבי" disable_confirm: "לנטרל את כל האימותים הדו־שלביים?" - edit: "ערוך" + edit: "עריכה" edit_title: "עריכת אימות דו־שלבי" edit_description: "שם אימות דו־שלבי" enable_security_key_description: "כשמפתח האבטחה הפיזי שלך מוכן יש ללחוץ על כפתור הרישום שלהלן." @@ -1361,9 +1361,6 @@ he: enabled: "אתר זה נמצא במצב קריאה בלבד. אנא המשיכו לשוטט, אך תגובות, לייקים, ופעולות נוספות כרגע אינם מאופשרים." login_disabled: "הכניסה מנוטרלת בזמן שהאתר במצב קריאה בלבד." logout_disabled: "היציאה מנוטרלת בזמן שהאתר במצב של קריאה בלבד." - too_few_topics_and_posts_notice: "הבה נתחיל להתדיין! כרגע ישנם %{currentTopics} נושאים ו־%{currentPosts} פוסטים. המבקרים זקוקים ליותר תוכן כדי לקרוא ולהגיב להם - אנו ממליצים על %{requiredTopics} נושאים ו־%{requiredPosts} פוסטים לפחות. רק הסגל יכול לראות את ההודעה הזאת." - too_few_topics_notice: "הבה נתחיל להתדיין! כרגע ישנם %{currentTopics} נושאים – המבקרים זקוקים ליותר תוכן כדי להגיב - אנו ממליצים על %{requiredTopics} נושאים לפחות. רק הסגל יכול לראות את ההודעה הזאת." - too_few_posts_notice: "הבה נתחיל להתדיין! כרגע ישנם %{currentPosts} פוסטים. המבקרים זקוקים ליותר תוכן כדי להגיב - אנו ממליצים על %{requiredPosts} פוסטים לפחות. רק הסגל יכול לראות את ההודעה הזאת." logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {שגיאה אחת בשעה הגיעה} other {# שגיאות בשעה הגיעו}} למגבלת האתר שהיא {limit, plural, one {שגיאה אחת בשעה} other {# שגיאות בשעה}}." reached_minute_MF: "{relativeAge}{rate, plural, one {שגיאה אחת בדקה הגיעה} other {# שגיאות בדקה הגיעו}} למגבלת האתר שהיא {limit, plural, one {שגיאה אחת בדקה} other {# שגיאות בדקה}}." @@ -1381,7 +1378,7 @@ he: day: "יום" first_post: פוסט ראשון mute: השתק - unmute: בטל השתקה + unmute: ביטול השתקה last_post: פורסמו time_read: נקרא time_read_recently: "%{time_read} לאחרונה" @@ -1414,7 +1411,7 @@ he: private_message_info: title: "הודעה" invite: "הזמינו אחרים..." - edit: "הוסף או הסר..." + edit: "הוספה או הסרה…" leave_message: "האם אתה באמת רוצה לעזוב את ההודעה הזו?" remove_allowed_user: "להסיר את {{name}} מהודעה זו?" remove_allowed_group: "להסיר את {{name}} מהודעה זו?" @@ -1620,7 +1617,7 @@ he: saved_local_draft_tip: "נשמר מקומית" similar_topics: "הנושא שלך דומה ל..." drafts_offline: "טיוטות מנותקות" - edit_conflict: "ערוך קונפליקט." + edit_conflict: "עריכת סתירה" group_mentioned_limit: "זהירות! ציינת {{group}}, אך לקבוצה זו יש יותר חברים משהוגדר למנהל המערכת הגבלה של עד {{max}} משתמשים. אף אחד לא יקבל הודעה" group_mentioned: one: "על ידי אזכור {{group}}, אתם עומדים ליידע אדם אחד – אתם בטוחים?" @@ -1652,7 +1649,7 @@ he: create_pm: "הודעה" create_whisper: "לחישה" create_shared_draft: "צור טיוטה משותפת" - edit_shared_draft: "ערוך טויטה משותפת" + edit_shared_draft: "עריכת טיוטה משותפת" title: "או לחצו Ctrl+Enter" users_placeholder: "הוספת משתמש" title_placeholder: " במשפט אחד, במה עוסק הדיון הזה?" @@ -1709,7 +1706,7 @@ he: composer_actions: reply: השב draft: טיוטה - edit: ערוך + edit: עריכה reply_to_post: label: "תגובה לפוסט %{postNumber} ע\"י %{postUsername}" desc: תגובה לפוסט ספיציפי @@ -1990,7 +1987,7 @@ he: help: "החזרת הודעה לדואר נכנס" edit_message: help: "ערוך פוסט ראשון של ההודעה" - title: "ערוך הודעה" + title: "עריכת הודעה" defer: help: "סימון כלא נקראו" title: "אחר כך" @@ -2055,7 +2052,7 @@ he: group_join: "עליך להצטרף לקבוצה `{{name}}` כדי לצפות בנושא הזה" group_request_sent: "בקשת החברות שלך נשלחה לקבוצה הזו. ניידע אותך כשהיא תתקבל." unread_indicator: "אף אחד מהחברים לא קרא את הפוסט האחרון של הנושא הזה עדיין." - read_more_MF: "יש { UNREAD, plural, =0 {} one { 1 שלא נקרא } other { # שלא נקראו } } { NEW, plural, =0 {} one { {BOTH, select, true{ו} false {} other{}} נושא חדש אחד} other { {BOTH, select, true{ו} false {} other{}} # נושאים חדשים} } נותרים, or {CATEGORY, select, true {עיין בנושאים אחרים ב {catLink}} false {{latestLink}} other {}}" + read_more_MF: "יש { UNREAD, plural, =0 {} one { 1 שלא נקרא } other { # שלא נקראו } } { NEW, plural, =0 {} one { {BOTH, select, true{ו} false {} other{}} נושא חדש אחד} other { {BOTH, select, true{ו} false {} other{}} # נושאים חדשים} } נותרים, או {CATEGORY, select, true {עיין בנושאים אחרים ב־{catLink}} false {{latestLink}} other {}}" browse_all_categories: עיינו בכל הקטגוריות view_latest_topics: הצגת נושאים אחרונים suggest_create_topic: "למה לא ליצור נושא חדש?" @@ -2616,7 +2613,7 @@ he: none: "(ללא קטגוריה)" all: "כל הקטגוריות" choose: "קטגוריה…" - edit: "ערוך" + edit: "עריכה" edit_dialog_title: "עריכה: %{categoryName}" view: "הצגת נושאים בקטגוריה" general: "כללי" @@ -2635,7 +2632,7 @@ he: min_tags_from_required_group_label: "מס׳ תגיות:" required_tag_group_label: "קבוצת תגיות:" topic_featured_link_allowed: "אפשרו קישורים מומלצים בקטגוריה זו" - delete: "מחק קטגוריה" + delete: "מחיקת קטגוריה" create: "קטגוריה חדשה" create_long: "יצירת קטגוריה חדשה" save: "שמירת קטגוריה" @@ -2657,7 +2654,7 @@ he: delete_error: "ארעה שגיאה במחיקת הקטגוריה." list: "הצג קטגוריות" no_description: "אנא הוסיפו תיאור לקטגוריה זו." - change_in_category_topic: "ערוך תיאור" + change_in_category_topic: "עריכת תיאור" already_used: "הצבע הזה בשימוש על ידי קטגוריה אחרת" security: "אבטחה" special_warning: "אזהרה: קטגוריה זו הגיעה מראש והגדרות האבטחה שלה אינן ניתנות לשינוי. אם אתם מעוניינים להשתמש בקטגוריה זו, מחקו אותה במקום להשתמש בה מחדש." @@ -2679,7 +2676,7 @@ he: default_view: "תצוגת ברירת מחדל לנושאים:" default_top_period: "פרק זמן דיפולטיבי להובלה" allow_badges_label: "לאפשר הענקת עיטורים בקטגוריה זו" - edit_permissions: "ערוך הרשאות" + edit_permissions: "עריכת הרשאות" reviewable_by_group: "בנוסף לסגל, פוסטים ודגלים בקטגוריה הזאת יכולים להיות נתונים גם לסקירתם של:" review_group_name: "שם הקבוצה" require_topic_approval: "לדרוש אישור מפקח לכל הנושאים החדשים" @@ -2822,6 +2819,7 @@ he: help: "נושא זה מוסתר; הוא לא יוצג ברשימות הנושאים, וזמין רק באמצעות קישור ישיר." personal_message: title: "הנושא הזה הוא הודעה אישית" + help: "הנושא הזה הוא הודעה אישית" posts: "פוסטים" posts_long: "יש {{number}} פוסטים בנושא הזה" posts_likes_MF: | @@ -2885,10 +2883,10 @@ he: unread: title: "לא-נקראו" title_with_count: - one: "לא נקרא (%{count})" + one: "לא נקראה (%{count})" two: "לא-נקראו ({{count}})" many: "לא-נקראו ({{count}})" - other: "לא-נקראו ({{count}})" + other: "לא נקראו ({{count}})" help: "נושאים שאתם כרגע צופים או עוקבים אחריהם עם פוסטים שלא נקראו" lower_title_with_count: one: "לא נקרא (%{count})" @@ -3097,7 +3095,7 @@ he: add_synonyms_failed: "לא ניתן להוסיף את התגיות הבאות בתור מילים נרדפות: %{tag_names}. נא לוודא שאין להן מילים נרדפות ושאינן כבר מילים נרדפות של תגית אחרת." remove_synonym: "הסרת מילה נרדפת" delete_synonym_confirm: 'למחוק את המילה הנרדפת „%{tag_name}”?' - delete_tag: "מחק תגית" + delete_tag: "מחיקת תגית" delete_confirm: one: "למחוק את התגית הזו ולהסיר אותה מהנושא אליו היא מוקצית?" two: "למחוק את התגית הזו ולהסיר אותה משני הנושאים אליהן היא מוקצית?" @@ -3346,14 +3344,14 @@ he: primary: "קבוצה ראשית" no_primary: "(אין קבוצה ראשית)" title: "קבוצות" - edit: "ערוך קבוצות" + edit: "עריכת קבוצות" refresh: "רענן" - about: "ערוך את חברות הקבוצה שלך והשמות כאן" + about: "עריכת חברות הקבוצה שלך והשמות כאן" group_members: "חברי הקבוצה" - delete: "מחק" + delete: "מחיקה" delete_confirm: "להסיר קבוצה זו?" delete_failed: "לא ניתן להסיר קבוצה זו. אם זו קבוצה אוטומטית, היא בלתי ניתנת למחיקה." - delete_owner_confirm: "הסרת הרשאות מנהל עבור '%{username}'?" + delete_owner_confirm: "להסיר את הרשאות הניהול של ‚%{username}’?" add: "הוספה" custom: "מותאם" automatic: "אוטומטי" @@ -3548,7 +3546,7 @@ he: title: "שליחת הודעה בדוא״ל עם קישור להורדה" alert: "קישור להורדת גיבוי זה נשלח אליכם." destroy: - title: "הסר את הגיבוי" + title: "הסרת הגיבוי" confirm: "להשמיד את הגיבוי הזה?" restore: is_disabled: "שחזור אינו מאופשר לפי הגדרות האתר." @@ -3587,11 +3585,11 @@ he: new: "חדש" new_style: "סגנון חדש" install: "התקנה" - delete: "מחק" + delete: "מחיקה" delete_confirm: 'למחוק את „%{theme_name}”?' color: "צבע" opacity: "שקיפות" - copy: "העתק" + copy: "העתקה" copy_to_clipboard: "העתקה ללוח" copied_to_clipboard: "הועתק ללוח" copy_to_clipboard_error: "שגיאה בהעתקת מידע ללוח" @@ -3603,7 +3601,7 @@ he: body: "גוף" none_selected: "בחרו תבנית דואר אלקטרוני לעריכה." revert: "ביטול שינויים" - revert_confirm: "האם ברצונכם לבטל את השינויים?" + revert_confirm: "לבטל את השינויים שלך?" theme: theme: "ערכת עיצוב" component: "רכיב" @@ -3891,8 +3889,8 @@ he: topic_id: "זהות (ID) נושא" post_id: "מזהה פוסט" category_id: "מזהה קטגוריה" - delete: "מחק" - edit: "ערוך" + delete: "מחיקה" + edit: "עריכה" save: "שמור" screened_actions: block: "חסום" @@ -3916,7 +3914,7 @@ he: no_previous: "אין ערך קודם." deleted: "אין ערך חדש. הרשומה נמחקה." actions: - delete_user: "מחק משתמש" + delete_user: "מחיקת משתמש" change_trust_level: "שנוי דרגת אמון" change_username: "שינוי שם משתמש/ת" change_site_setting: "שנוי הגדרות אתר" @@ -4018,7 +4016,7 @@ he: form: label: "חדש:" ip_address: "כתובת IP" - add: "הוסף" + add: "הוספה" filter: "חיפוש" roll_up: text: "גלגול (Roll up)" @@ -4085,7 +4083,7 @@ he: invalid: "סליחה, אך אינך מורשה להתחזות למשתמש הזה." users: title: "משתמשים" - create: "הוסף מנהל" + create: "הוספת מנהל" last_emailed: "נשלח בדואר אלקטרוני לאחרונה" not_found: "סליחה, שם המשתמש הזה אינו קיים במערכת שלנו." id_not_found: "מצטערים, זהות המשתמש/ת אינה קיימת במערכת שלנו." @@ -4142,13 +4140,13 @@ he: silence_message_placeholder: "(להשאיר ריק כדי לשלוח את הודעת בררת המחדל)" suspended_until: "(עד %{until})" cant_suspend: "אי אפשר להשעות את המשתמש הזה." - delete_all_posts: "מחק את כל הפוסטים" + delete_all_posts: "מחיקת כל הפוסטים" delete_posts_progress: "פוסטים נמחקים…" delete_posts_failed: "אירעה תקלה בעת מחיקת הפוסטים." penalty_post_actions: "מה לעשות עם הפוסט המשויך?" penalty_post_delete: "למחוק את הפוסט" penalty_post_delete_replies: "למחוק את הפוסט על תגובותיו" - penalty_post_edit: "לערוך את הפוסט" + penalty_post_edit: "עריכת הפוסט" penalty_post_none: "לא לעשות דבר" penalty_count: "ספירת עונשין" clear_penalty_history: @@ -4202,7 +4200,7 @@ he: anonymize_confirm: "באמת<\\b> להפוך חשבון זה לאלמוני? פעולה זו תשנה את שם המשתמש ואת כתובת הדוא״ל ותאפס את כל נתוני הפרופיל." anonymize_yes: "כן, נא להפוך חשבון זה לאלמוני" anonymize_failed: "אירעה תקלה בהפיכת חשבון זה לאלמוני." - delete: "מחק משתמש/ת" + delete: "מחיקת משתמש" delete_forbidden_because_staff: "לא ניתן למחוק מנהלים ומפקחים." delete_posts_forbidden_because_staff: "לא ניתן להסיר את כל הפוסטים של מנהלי מערכת ומפקחים." delete_forbidden: @@ -4335,7 +4333,7 @@ he: search: "חפשו טקסט שברצונכם לערוך" title: "טקסט" edit: "ערוך" - revert: "בטל שינויים" + revert: "ביטול שינויים" revert_confirm: "לבטל את השינויים שלך?" go_back: "חזרה לחיפוש" recommended: "אנו ממליצים לערוך את הטקסט הבא כדי שיתאים לצרכים שלך:" @@ -4349,7 +4347,7 @@ he: title: "הגדרות" no_results: "לא נמצאו תוצאות." more_than_30_results: "יש למעלה מ־50 תוצאות. נא למקד את החיפוש שלך." - clear_filter: "נקה" + clear_filter: "ניקוי" add_url: "הוספת כתובת URL" add_host: "הוספת שרת" add_group: "הוספת קבוצה" @@ -4413,7 +4411,7 @@ he: granted_at: הוענק ב reason_help: (קישור לפוסט או לנושא) save: שמור - delete: מחק + delete: מחיקה delete_confirm: "למחוק את העיטור הזה?" revoke: שלול reason: סיבה diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index 3cf3589187..a58d8484b1 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -27,6 +27,7 @@ it: millions: "{{number}}M" dates: time: "h:mm a" + time_short_day: "ddd, HH:mm" timeline_date: "MMM YYYY" long_no_year: "D MMM h:mm a" long_no_year_no_time: "D MMM" @@ -56,7 +57,7 @@ it: other: "%{count}m" about_x_hours: one: "%{count}ora" - other: "%{count}ore" + other: "%{count} ore" x_days: one: "%{count}giorno" other: "%{count}giorni" @@ -77,7 +78,7 @@ it: medium: x_minutes: one: "%{count} min" - other: "%{count}min" + other: "%{count} min" x_hours: one: "%{count} ora" other: "%{count} ore" @@ -88,10 +89,10 @@ it: medium_with_ago: x_minutes: one: "%{count} minuto fa" - other: "%{count}minuti fa" + other: "%{count} minuti fa" x_hours: one: "%{count} ora fa" - other: "%{count}ore fa" + other: "%{count} ore fa" x_days: one: "%{count} giorno fa" other: "%{count}giorni fa" @@ -107,7 +108,7 @@ it: other: "%{count}giorni dopo" x_months: one: "%{count} mese dopo" - other: "%{count}mesi dopo" + other: "%{count} mesi dopo" x_years: one: "%{count} anno dopo" other: "%{count}anni dopo" @@ -152,6 +153,8 @@ it: banner: enabled: "lo ha reso un annuncio il %{when}. Apparirà in cima ad ogni pagina finché non verrà chiuso dall'utente. " disabled: "ha rimosso questo banner il %{when}. Non apparirà più in cima ad ogni pagina." + forwarded: "inoltrato l'e-mail qui sopra" + topic_admin_menu: "azioni argomento" wizard_required: "Benvenuto al tuo nuovo Discourse! Inizia la procedura guidata di configurazione ✨" emails_are_disabled: "Tutte le email in uscita sono state disabilitate a livello globale da un amministratore. Non sarà inviato nessun tipo di notifica via email." bootstrap_mode_enabled: "Per aiutarti ad avviare il tuo nuovo sito, adesso sei in modalità bootstrap. Tutti i nuovi utenti saranno automaticamente promossi al livello di esperienza 1 e riceveranno il riepilogo quotidiano degli aggiornamenti via email. Questa modalità sarà disattivata automaticamente quando avrai più di %{min_users}utenti iscritti." @@ -261,9 +264,19 @@ it: bookmarks: created: "hai inserito questo messaggio nei segnalibri" not_bookmarked: "aggiungi ai segnalibri" + created_with_reminder: "hai aggiunto questo messaggio ai segnalibri con un promemoria il%{date}" remove: "Rimuovi Segnalibro" confirm_clear: "Sei certo di voler rimuovere tutti i segnalibri da questo argomento?" save: "Salva" + no_timezone: 'Non hai ancora impostato un fuso orario. Non sarai in grado di impostare promemoria. Creane uno nel tuo profilo .' + reminders: + at_desktop: "La prossima volta che sarò al mio desktop" + later_today: "Più tardi, oggi
{{date}}" + next_business_day: "Il prossimo giorno lavorativo
{{date}}" + tomorrow: "Domani
{{date}}" + next_week: "La prossima settimana
{{date}}" + next_month: "Il prossimo mese
{{date}}" + custom: "Data e ora personalizzate" drafts: resume: "Riprendi" remove: "Rimuovi" @@ -309,8 +322,14 @@ it: install_banner: "Vuoi installare %{title} su questo dispositivo?" choose_topic: none_found: "Nessun argomento trovato." + title: + search: "Cerca un argomento" + placeholder: "digita qui il titolo dell'argomento, l'URL o l'id" choose_message: none_found: "Nessun messaggio trovato." + title: + search: "Cerca un messaggio" + placeholder: "digita qui il titolo del messaggio, l'URL o l'id" review: order_by: "Ordina per" in_reply_to: "in risposta a" @@ -347,7 +366,7 @@ it: delete: "Elimina" settings: saved: "Salvato" - save_changes: "Salva Modifiche" + save_changes: "Salva le modifiche" title: "Impostazioni" priorities: title: "Priorità Revisionabili" @@ -368,6 +387,7 @@ it: deleted_user: "(utente eliminato)" user: bio: "Biografia" + website: "Sito web" username: "Nome utente" email: "Email" name: "Nome" @@ -559,6 +579,8 @@ it: leave: "Abbandona" request: "Richiesta" message: "Messaggio" + confirm_leave: "Sei sicuro di voler abbandonare questo gruppo?" + allow_membership_requests: "Consenti agli utenti di inviare richieste di ammissione ai proprietari dei gruppi (richiede un gruppo visibile pubblicamente)" membership_request_template: "Modello personalizzato da mostrare agli utenti quando inviano una richiesta di adesione" membership_request: submit: "Invia Richiesta" @@ -737,9 +759,13 @@ it: activity_stream: "Attività" preferences: "Opzioni" feature_topic_on_profile: + open_search: "Seleziona un nuovo argomento" + title: "Seleziona un argomento" + search_label: "Cerca argomento per titolo" save: "Salva" clear: title: "Pulisci" + warning: "Sei sicuro di voler cancellare l'argomento in primo piano?" profile_hidden: "Il profilo pubblico di questo utente è nascosto." expand_profile: "Espandi" collapse_profile: "Raggruppa" @@ -772,6 +798,7 @@ it: enable_quoting: "Abilita \"rispondi quotando\" per il testo evidenziato" enable_defer: "Abilita il rinvio per contrassegnare gli argomenti come non letti" change: "cambia" + featured_topic: "Argomento in primo piano" moderator: "{{user}} è un moderatore" admin: "{{user}} è un amministratore" moderator_tooltip: "Questo utente è un moderatore" @@ -795,7 +822,7 @@ it: warning: "Modalità Mailing List attiva. Le impostazioni per la notifica via email verranno ignorate." tag_settings: "Etichette" watched_tags: "Osservate" - watched_tags_instructions: "Osserverai automaticamente tutti gli argomenti con queste etichette. Verrai notificato di tutti i nuovi messaggi e argomenti, e accanto all'argomento apparirà anche un conteggio dei nuovi messaggi." + watched_tags_instructions: "Osserverai automaticamente tutti gli argomenti con questi tag. Verrai notificato di tutti i nuovi messaggi e argomenti, e accanto all'argomento apparirà anche un conteggio dei nuovi messaggi." tracked_tags: "Seguite" tracked_tags_instructions: "Seguirai automaticamente tutti gli argomenti con queste etichette. Accanto all'argomento apparirà il conteggio dei nuovi messaggi." muted_tags: "Silenziati" @@ -809,8 +836,8 @@ it: watched_first_post_tags: "Osservando Primo Messaggio" watched_first_post_tags_instructions: "Riceverai la notifica per il primo messaggio di ogni nuovo argomento con queste etichette." muted_categories: "Silenziate" - muted_categories_instructions: "Non riceverai notifiche relative a nuovi Argomenti in queste Categorie, e non appariranno nella pagina delle Categorie o dei Recenti." - muted_categories_instructions_dont_hide: "Non riceverai alcuna notifica per i nuovi Argomenti creati in questa categoria." + muted_categories_instructions: "Non riceverai notifiche riguardanti i contenuti di queste categorie, e non appariranno nelle pagine delle Categorie o dei Recenti." + muted_categories_instructions_dont_hide: "Non riceverai alcuna notifica riguardante nuovi argomenti in queste categorie." no_category_access: "Come moderatore hai accesso limitato alla categoria, il salvataggio è disabilitato." delete_account: "Cancella il mio account" delete_account_confirm: "Sei sicuro di voler cancellare il tuo account in modo permanente? Questa azione non può essere annullata!" @@ -929,7 +956,7 @@ it: error: "Si è verificato un errore durante la modifica del valore." change_username: title: "Cambia Utente" - confirm: "Sei assolutamente certo di voler cambiare il tuo nome utente?" + confirm: "Sei sicuro di voler davvero cambiare il tuo nome utente?" taken: "Spiacenti, questo nome utente è già riservato." invalid: "Nome utente non valido: usa solo lettere e cifre" change_email: @@ -955,6 +982,9 @@ it: change_card_background: title: "Sfondo Scheda Utente" instructions: "Le immagini di sfondo saranno centrate e per difetto avranno un'ampiezza di 590px." + change_featured_topic: + title: "Argomento in primo piano" + instructions: "Un collegamento a questo argomento sarà sulla tua scheda utente e profilo." email: title: "Email" primary: "Email principale" @@ -1090,6 +1120,7 @@ it: search: "digita per cercare inviti..." title: "Inviti" user: "Utente Invitato" + sent: "Ultimo inviato" none: "Nessun invito da visualizzare." truncated: one: "Mostro il primo invito." @@ -2559,6 +2590,7 @@ it: help: "Questo argomento è invisibile; non verrà mostrato nella liste di argomenti ed è possibile accedervi solo tramite collegamento diretto" personal_message: title: "Questo Argomento è un Messaggio Personale" + help: "Questo Argomento è un Messaggio Personale" posts: "Messaggi" posts_long: "ci sono {{number}} messaggi in questo argomento" posts_likes_MF: | diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 3e3da3ffae..9cbacc231d 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -1261,9 +1261,12 @@ nl: enabled: "Deze website bevindt zich in alleen-lezenmodus. U kunt doorgaan met browsen, maar berichten beantwoorden, likes geven en andere acties zijn momenteel uitgeschakeld." login_disabled: "Aanmelden is uitgeschakeld zolang de website zich in alleen-lezenmodus bevindt." logout_disabled: "Afmelden is uitgeschakeld zolang de website zich in alleen-lezenmodus bevindt." - too_few_topics_and_posts_notice: "Laten we de discussie starten! Er zijn %{currentTopics} topics en %{currentPosts} berichten. Bezoekers hebben er meer nodig om te lezen en op te antwoorden – minstens %{requiredTopics} topics en %{requiredPosts} berichten wordt aanbevolen. Alleen stafleden kunnen dit bericht zien." - too_few_topics_notice: "Laten we de discussie starten! Er zijn %{currentTopics} topics. Bezoekers hebben er meer nodig om te lezen en op te antwoorden – minstens %{requiredTopics} topics wordt aanbevolen. Alleen stafleden kunnen dit bericht zien." - too_few_posts_notice: "Laten we de discussie starten! Er zijn %{currentPosts} berichten. Bezoekers hebben er meer nodig om te lezen en op te antwoorden – minstens %{requiredPosts} berichten wordt aanbevolen. Alleen stafleden kunnen dit bericht zien." + too_few_topics_and_posts_notice_MF: >- + Laten we de discussie starten! Er {currentTopics, plural, one {is # topic} other {zijn # topics}} en {currentPosts, plural, one {# bericht} other {# berichten}}. Bezoekers hebben er meer nodig om te lezen en op te antwoorden – minstens {requiredTopics, plural, one {# topic} other {# topics}} en {requiredPosts, plural, one {# bericht} other {# berichten}} wordt aanbevolen. Alleen stafleden kunnen dit bericht zien. + too_few_topics_notice_MF: >- + Laten we de discussie starten! Er {currentTopics, plural, one {is # topic} other {zijn # topics}}. Bezoekers hebben er meer nodig om te lezen en op te antwoorden – minstens {requiredTopics, plural, one {# topic} other {# topics}} wordt aanbevolen. Alleen stafleden kunnen dit bericht zien. + too_few_posts_notice_MF: >- + Laten we de discussie starten! Er {currentPosts, plural, one {is # bericht} other {zijn # berichten}}. Bezoekers hebben er meer nodig om te lezen en op te antwoorden – minstens {requiredPosts, plural, one {# bericht} other {# berichten}} wordt aanbevolen. Alleen stafleden kunnen dit bericht zien. logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# fout/uur} other {# fouten/uur}} heeft de limiet voor de website-instelling van {limit, plural, one {# fout/uur} other {# fouten/uur}} bereikt." reached_minute_MF: "{relativeAge}{rate, plural, one {# fout/minuut} other {# fouten/minuut}} heeft de limiet voor de website-instelling van {limit, plural, one {# fout/minuut} other {# fouten/minuut}} bereikt." @@ -2626,6 +2629,7 @@ nl: help: "Dit topic is niet zichtbaar; het verschijnt niet in topiclijsten en kan alleen via een rechtstreekse koppeling worden benaderd" personal_message: title: "Dit topic is een persoonlijk bericht" + help: "Dit topic is een persoonlijk bericht" posts: "Berichten" posts_long: "er zijn {{number}} berichten in dit topic" posts_likes_MF: | diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 7f44991962..a6bfdba8c2 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -1304,9 +1304,6 @@ pl_PL: enabled: "Strona jest w trybie tylko-do-odczytu. Możesz nadal przeglądać serwis, ale operacje takie jak postowanie, lajkowanie i inne są wyłączone." login_disabled: "Logowanie jest zablokowane, gdy strona jest w trybie tylko do odczytu." logout_disabled: "Wylogowanie jest zablokowane gdy strona jest w trybie tylko do odczytu." - too_few_topics_and_posts_notice: "Rozpocznijmy dyskusję! Istnieje %{currentTopics} tematów i %{currentPosts} postów. Goście muszą więcej czytać i odpowiadać - zalecamy przynajmniej %{requiredTopics} tematów i %{requiredPosts} posty. Tylko pracownicy mogą zobaczyć tę wiadomość." - too_few_topics_notice: "Zacznijmy dyskusję! Jest %{currentTopics} tematów. Odwiedzający potrzebują więcej do przeczytania i odpowiedzi - zalecamy co najmniej %{requiredTopics} tematów. Tylko pracownicy mogą zobaczyć tę wiadomość." - too_few_posts_notice: "Zacznijmy dyskusję! Jest %{currentPosts} postów. Odwiedzający potrzebują więcej, aby przeczytać i odpowiedzieć - zalecamy co najmniej %{requiredPosts} postów. Tylko pracownicy mogą zobaczyć tę wiadomość." learn_more: "dowiedz się więcej…" all_time: "łącznie" all_time_desc: "łącznie utworzonych tematów" diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index bdc87c1e8d..a792d11c64 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -1257,9 +1257,6 @@ pt_BR: enabled: "Este site está em modo de somente leitura. Por favor, continue a navegar, mas respostas, curtidas e outras ações estão desabilitadas por enquanto." login_disabled: "O login é desabilitado enquanto o site está em modo de somente leitura." logout_disabled: "O logout é desabilitado enquanto o site está em modo de somente leitura." - too_few_topics_and_posts_notice: "Vamos iniciar a discussão!%{currentTopics} tópicos e %{currentPosts} postagens. Os visitantes precisam de mais informações para ler e responder - nós recomendamos pelo menos %{requiredTopics} tópicos e %{requiredPosts} posts. Somente funcionários podem ver esta mensagem." - too_few_topics_notice: "Vamos iniciar a discussão!%{currentTopics} tópicos. Os visitantes precisam de mais informações para ler e responder - nós recomendamos pelo menos %{requiredTopics} tópicos. Somente funcionários podem ver esta mensagem." - too_few_posts_notice: "Vamos inicar a discussão!%{currentPosts} postagens. Os visitantes precisam de mais informações para ler e responder - nós recomendamos pelo menos %{requiredPosts} postagens. Somente funcionários podem ver esta mensagem." logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# erro/hora} other {# erros/hora}} alcançou o limite de configuração do site de {limit, plural, one {# erro/hora} other {# erros/hora}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# erro/minuto} other {# erros/minuto}} alcançou o limite de configuração do site de {limit, plural, one {# erro/minuto} other {# erros/minuto}}." @@ -2613,6 +2610,7 @@ pt_BR: help: "Este tópico não está listado; ele não será exibido em listas de tópicos e só pode ser acessado por meio de um link direto" personal_message: title: "Este tópico é uma mensagem pessoal" + help: "Este tópico é uma mensagem pessoal" posts: "Postagens" posts_long: "há {{number}} mensagens neste tópico" posts_likes_MF: | diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 987c958f7a..72064bfd92 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -426,7 +426,7 @@ ru: title: "Обзорные приоритеты" moderation_history: "История модерации" view_all: "Посмотреть все" - grouped_by_topic: "Сгруппированы по темам" + grouped_by_topic: "Сгруппированные по темам" none: "Нет элементов для премодерации." view_pending: "просмотр в ожидании" topic_has_pending: @@ -1361,9 +1361,12 @@ ru: enabled: "Сайт работает в режиме \"только для чтения\". Сейчас вы можете продолжать просматривать сайт, но другие действия будут недоступны. " login_disabled: "Вход отключён, пока сайт в режиме «только для чтения»" logout_disabled: "Выход отключён, пока сайт в режиме «только для чтения»" - too_few_topics_and_posts_notice: "Давайте приступим к обсуждению! Есть %{currentTopics} тем и %{currentPosts} постов. Пользователи должны больше читать и отвечать – мы рекомендуем, по крайней мере %{requiredTopics} тем и %{requiredPosts} постов. Только сотрудники могут видеть это сообщение." - too_few_topics_notice: "Давайте приступим к обсуждению! Есть %{currentTopics} тем. Пользователи должны больше читать и отвечать – мы рекомендуем, по крайней мере %{requiredTopics} тем. Только сотрудники могут видеть это сообщение." - too_few_posts_notice: "Давайте приступим к обсуждению! Есть %{currentPosts} сообщений. Пользователям нужно больше читать и отвечать - мы рекомендуем хотя бы %{requiredPosts} сообщений. Только сотрудники могут видеть это сообщение." + too_few_topics_and_posts_notice_MF: >- + Давайте приступим к обсуждению! Есть {currentTopics, plural, one {# тема} few {# темы} other {# тем}} и {currentPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Пользователи должны больше читать и отвечать – мы рекомендуем, по крайней мере {requiredTopics, plural, one {# тему} few {# темы} other {# тем}} и {requiredPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Только сотрудники могут видеть это сообщение. + too_few_topics_notice_MF: >- + Давайте приступим к обсуждению! Есть {currentTopics, plural, one {# тема} few {# темы} other {# тем}}. Пользователи должны больше читать и отвечать – мы рекомендуем, по крайней мере {requiredTopics, plural, one {# тему} few {# темы} other {# тем}}. Только сотрудники могут видеть это сообщение. + too_few_posts_notice_MF: >- + Давайте приступим к обсуждению! Есть {currentPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Пользователи должны больше читать и отвечать – мы рекомендуем, по крайней мере {requiredPosts, plural, one {# сообщение} few {# сообщения} other {# сообщений}}. Только сотрудники могут видеть это сообщение. logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} или {# errors/hour}} достигнут предел настройки сайта {limit, plural, one {# error/hour} или {# errors/hour}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} или {# errors/minute}} достигнут предел настройки сайта {limit, plural, one {# error/minute} или {# errors/minute}}." @@ -2055,7 +2058,7 @@ ru: group_join: "Вам нужно присоединиться к группе `{{name}}` чтобы увидеть эту тему." group_request_sent: "Ваш запрос на членство в группе был отправлен. Вам сообщат, когда будет одобрено." unread_indicator: "Никто еще не дочитал до конца этой темы." - read_more_MF: "У вас осталось { UNREAD, plural, =0 {} one { 1 непрочитанная } other { # непрочитанных } } { NEW, plural, =0 {} one { {BOTH, select, true{и } false { } other{}} 1 новая тема} other { {BOTH, select, true{и } false { } other{}} # новых тем} }, вы также можете {CATEGORY, select, true {посмотреть другие темы в разделе {catLink}} false {{latestLink}} other {}}" + read_more_MF: "У вас осталось { UNREAD, plural, =0 {} one { 1 непрочитанная } few { 1 непрочитанные } other { # непрочитанных } } { NEW, plural, =0 {} one { {BOTH, select, true{и } false { } other{}} 1 новая тема} other { {BOTH, select, true{и } false { } other{}} # новых тем} }, вы также можете {CATEGORY, select, true {посмотреть другие темы в разделе {catLink}} false {{latestLink}} other {}}" browse_all_categories: Просмотреть все разделы view_latest_topics: посмотреть последние темы suggest_create_topic: "Почему бы вам не создать новую тему?" @@ -2615,7 +2618,7 @@ ru: can: "может… " none: "(вне раздела)" all: "Все разделы" - choose: "разделе…" + choose: "Выберите раздел…" edit: "Изменить" edit_dialog_title: "Редактировать: %{categoryName}" view: "Просмотр тем по разделам" @@ -2747,7 +2750,7 @@ ru: notify_action: "Сообщение" official_warning: "Официальное предупреждение" delete_spammer: "Удалить спамера" - delete_confirm_MF: "Вы собираетесь удалить {POSTS, plural, one {1 сообщение} other {# сообщений}} и {TOPICS, plural, one {1 тему} other {# темы}} этого пользователя, а так же удалить его учётную запись, добавить его IP-адрес {ip_address} и его почтовый адрес {email} в чёрный список. Вы действительно действительно ваши помыслы чисты и действия не продиктованы гневом?" + delete_confirm_MF: "Вы собираетесь удалить {POSTS, plural, one {1 сообщение} few {# сообщения} other {# сообщений}} и {TOPICS, plural, one {1 тему} few {# темы} other {# тем}} этого пользователя, а так же удалить его учётную запись, добавить его IP-адрес {ip_address} и его почтовый адрес {email} в чёрный список. Вы действительно действительно ваши помыслы чисты и действия не продиктованы гневом?" yes_delete_spammer: "Да, удалить спамера" ip_address_missing: "(не доступно)" hidden_email_address: "(скрыто)" @@ -2822,10 +2825,11 @@ ru: help: "Тема исключена из всех списков тем и доступна только по прямой ссылке" personal_message: title: "Эта тема является личным сообщением" + help: "Эта тема является личным сообщением" posts: "Сообщ." posts_long: "{{number}} сообщений в теме" posts_likes_MF: | - В этой теме {count, plural, one {1 сообщение} other {# сообщений}} {ratio, select, + В этой теме {count, plural, one {1 сообщение} few {# сообщения} other {# сообщений}} {ratio, select, low {с высоким рейтингом симпатий} med {с очень высоким рейтингом симпатий} high {с чрезвычайно высоким рейтингом симпатий} @@ -4154,10 +4158,10 @@ ru: clear_penalty_history: title: "Очистить историю штрафов" description: "пользователи со штрафами не могут достичь TL3" - delete_all_posts_confirm_MF: "Вы собираетесь удалить {POSTS, plural, one {1 сообщение} other {# сообщений}} и {TOPICS, plural, one {1 тему} other {# тем}}. Вы уверены?" + delete_all_posts_confirm_MF: "Вы собираетесь удалить {POSTS, plural, one {1 сообщение} few {# сообщения} other {# сообщений}} и {TOPICS, plural, one {1 тему} few {# темы} other {# тем}}. Вы уверены?" silence: "Заблокировать" unsilence: "Разблокировать" - silenced: "Заброкирован?" + silenced: "Заблокирован?" moderator: "Модератор?" admin: "Администратор?" suspended: "Заморожен?" diff --git a/config/locales/client.sl.yml b/config/locales/client.sl.yml index 51e69cbe17..3c84ec4ce6 100644 --- a/config/locales/client.sl.yml +++ b/config/locales/client.sl.yml @@ -2631,6 +2631,7 @@ sl: help: "Ta tema je izločena; ne bo se prikazovala na seznamih tem in se jo lahko dostopa samo preko neposredne povezave." personal_message: title: "Ta tema je zasebno sporočilo" + help: "Ta tema je zasebno sporočilo" posts: "Prispevki" posts_long: "{{number}} prispevkov v tej temi" posts_likes_MF: | diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index b58f1d3327..268b3d9cb1 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -796,7 +796,7 @@ sv: allow_private_messages: "Tillåt andra användare att skicka mig personliga meddelanden" external_links_in_new_tab: "Öppna alla externa länkar i en ny flik" enable_quoting: "Aktivera citatsvar för markerad text" - enable_defer: "Aktivera uppskjutning för att markera ämnen som lästa" + enable_defer: "Aktivera fördröjning för att markera ämnen som lästa" change: "ändra" featured_topic: "Utvalt Ämne" moderator: "{{user}} är en moderator" @@ -811,10 +811,9 @@ sv: email_activity_summary: "Aktivitetssammanfattning" mailing_list_mode: label: "Utskicksläge" - enabled: "Aktivera utskicksläge" + enabled: "Aktivera mottagning av e-post för varje nytt inlägg" instructions: | - Den här inställningen åsidosätter aktivitetssummeringen.
- Tystade ämnen och kategorier är inte inkluderade i de här e-postmeddelandena. + Den här inställningen åsidosätter aktivitetssummeringen.
Tystade ämnen och kategorier är inte inkluderade i de här e-postmeddelandena. individual: "Skicka ett e-postmeddelande för varje nytt inlägg." individual_no_echo: "Jag vill ha ett mail när nya poster publiceras" many_per_day: "Skicka ett e-postmeddelande för varje nytt inlägg (ungefär {{dailyEmailEstimate}} per dag)" @@ -851,7 +850,7 @@ sv: ignored_users: "Ignorerade" ignored_users_instructions: "Tysta alla inlägg och notifieringar från dessa användare." tracked_topics_link: "Visa" - automatically_unpin_topics: "Avklistra automatiskt ämnen när jag når botten." + automatically_unpin_topics: "Avklistra automatiskt ämnen när jag når botten" apps: "Appar" revoke_access: "Återkalla åtkomst" undo_revoke_access: "Ångra återkallelse av åtkomst" @@ -1262,9 +1261,12 @@ sv: enabled: "Webbplatsen är i skrivskyddat läge. Du kan fortsätta bläddra på sidan, men att skriva inlägg, gilla och andra interaktioner är inaktiverade för tillfället." login_disabled: "Det går inte att logga in medan siten är i skrivskyddat läge." logout_disabled: "Det går inte att logga ut medan webbplatsen är i skrivskyddat läge. " - too_few_topics_and_posts_notice: "Låt oss påbörja diskussionen! Det finns %{currentTopics} ämnen och %{currentPosts} inlägg. Besökare behöver mer att läsa och svara på – vi rekommenderar åtminstone %{requiredTopics} ämnen och %{requiredPosts} inlägg. Enbart personal kan se detta meddelande." - too_few_topics_notice: "Låt oss påbörja diskussionen! Det finns %{currentTopics} ämnen. Besökare behöver mer att läsa och svara på – vi rekommenderar åtminstone %{requiredTopics} ämnen. Enbart personal kan se detta meddelande." - too_few_posts_notice: "Låt oss påbörja diskussionen! Det finns %{currentPosts} inlägg. Besökare behöver mer att läsa och svara på – vi rekommenderar åtminstone %{requiredPosts} inlägg. Enbart personal kan se detta meddelande." + too_few_topics_and_posts_notice_MF: >- + Låt oss påbörja diskussionen! Det {currentTopics, plural, one {finns # ämne} other {finns # ämnen}} och {currentPosts, plural, one {# inlägg} other {# inlägg}}. Besökare behöver mer att läsa och svara på – vi rekommenderar åtminstone {requiredTopics, plural, one {# ämne} other {# ämnen}} och {requiredPosts, plural, one {# inlägg} other {# inlägg}}. Enbart personal kan se detta meddelande.  + too_few_topics_notice_MF: >- + Låt oss påbörja diskussionen! Det {currentTopics, plural, one {finns # ämne} other {finns # ämnen}}. Besökare behöver mer att läsa och svara på – vi rekommenderar åtminstone {requiredTopics, plural, one {# ämne} other {# ämnen}}. Enbart personal kan se detta meddelande.  + too_few_posts_notice_MF: >- + Låt oss påbörja diskussionen! Det {currentTopics, plural, one {finns # inlägg} other {finns # inlägg}}. Besökare behöver mer att läsa och svara på – vi rekommenderar åtminstone {requiredTopics, plural, one {# inlägg} other {# inlägg}}. Enbart personal kan se detta meddelande.  logs_error_rate_notice: reached_hour_MF: "{relativeAge} - {rate, plural, one {# error/hour} other {# errors/hour}} har uppnått webbplatsinställningarnas gräns på {limit, plural, one {# error/hour} other {# errors/hour}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} other {# errors/minute}} har uppnått weplatsinställningarnas gräns på {limit, plural, one {# error/minute} other {# errors/minute}}." @@ -2627,6 +2629,7 @@ sv: help: "Det här ämnet är olistat; det kommer inte visas i ämneslistorna och kan bara nås via en direktlänk" personal_message: title: "Detta ämne är ett personligt meddelande" + help: "Detta ämne är ett personligt meddelande" posts: "Inlägg" posts_long: "det finns {{number}} inlägg i detta ämne" posts_likes_MF: | diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index 7f9f612a6e..90724174ad 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -1258,9 +1258,6 @@ tr_TR: enabled: "Bu site salt-okunur modda. Lütfen taramaya devam et, ancak yanıtlama, beğenme ve diğer eylemler şu an için devre dışı durumda. " login_disabled: "Site salt-okunur modda iken giriş işlemi devre dışı bırakılır ." logout_disabled: "Site salt-okunur modda iken çıkış işlemi yapılamaz." - too_few_topics_and_posts_notice: "Haydi tartışma başlasın!Burada %{currentTopics} konu ve %{currentPosts} gönderi var. Ziyaretçilerin okuması ve yanıtlaması için tavsiye ettiğimiz en az %{requiredTopics} konu ve %{requiredPosts} gönderi. Bu mesajı yalnızca yetkili görebilir." - too_few_topics_notice: "Haydi tartışma başlasın!Burada %{currentTopics} konu var. Ziyaretçilerin okuması ve yanıtlaması için tavsiye ettiğimiz en az %{requiredTopics} konudur. Bu mesajı yalnızca yetkili görebilir." - too_few_posts_notice: "Haydi tartışma başlasın!Burada %{currentPosts} gönderi var. Ziyaretçilerin okuması ve yanıtlaması için tavsiye ettiğimiz en az %{requiredPosts} gönderidir. Bu iletiyi yalnızca yetkili görebilir." logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# hata/saat} diğeri {# hata/saat}} site limitlerine ulaştı {limit, plural, one {# hata/saat} other {# hata/saat}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# hata/saat} {# hata/dakika}} site limitlerine ulaştı {limit, plural, one {# hata/dakika} other {# hata/dakika}}." @@ -2617,6 +2614,7 @@ tr_TR: help: "Bu konu listelenmemiş; konu listelerinde görüntülenmeyecek ve sadece doğrudan bir bağlantı üzerinden erişilebilecek" personal_message: title: "Bu konu kişisel bir mesajdır" + help: "Bu konu kişisel bir mesajdır" posts: "Gönderiler" posts_long: "bu konuda {{number}} gönderi var" posts_likes_MF: | diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index 98f2e06b18..2ffafbd745 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -1361,9 +1361,6 @@ uk: enabled: "Сайт працює в режимі \"тільки для читання\". Зараз ви можете продовжувати переглядати сайт, але інші дії будуть недоступні. " login_disabled: "Вхід вимкнено, поки сайт перебуває в режимі лише для читання." logout_disabled: "Вихід відключений, поки сайт в режимі «тільки для читання»" - too_few_topics_and_posts_notice: "Давайте почнемо обговорення! Есть %{currentTopics} тем та %{currentPosts} постів. Користувачі повинні більше читати та відповідати - ми рекомендуємо, принаймні %{requiredTopics} тем та %{requiredPosts} постів. Тільки співробітники можуть бачити це повідомлення." - too_few_topics_notice: "Давайте почнемо обговорення! Есть %{currentTopics} тем. Користувачі повинні більше читати та відповідати - ми рекомендуємо, принаймні %{requiredTopics} тем. Тільки співробітники можуть бачити це повідомлення." - too_few_posts_notice: "Давайте почнемо обговорення! Есть %{currentPosts} постов. Користувачам потрібно більше читати та відповідати - ми рекомендуємо хоча б %{requiredPosts} постів. Тільки співробітники можуть бачити це повідомлення." logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} або {# errors/hour}} досягнуто максимально дозволене значення {limit, plural, one {# error/hour} або {# errors/hour}}." reached_minute_MF: "{relativeAge}{rate, plural, one {# error/minute} або {# errors/minute}} досягнуто максимально дозволене значення {limit, plural, one {# error/minute} або {# errors/minute}}." @@ -2822,6 +2819,7 @@ uk: help: "Тема виключена з усіх списків тем та доступна тільки за прямим посиланням" personal_message: title: "Ця тема є особистим повідомленням" + help: "Ця тема є особистим повідомленням" posts: "Дописи" posts_long: "тема містить {{number}} дописів" posts_likes_MF: | diff --git a/config/locales/client.ur.yml b/config/locales/client.ur.yml index 4f19680a0f..8187555885 100644 --- a/config/locales/client.ur.yml +++ b/config/locales/client.ur.yml @@ -1216,9 +1216,6 @@ ur: enabled: "یہ سائٹ صرف پڑھنے کے مَوڈ میں ہے۔ براہِ مہربانی براؤز کرتے رہئیے، لیکن جواب دینا، لائکس دینا، اور دیگر اعمال ابھی کے لئے غیر فعال ہیں۔" login_disabled: "جب تک سائٹ صرف پڑھنے کے مَوڈ میں ہے لاگ اِن غیر فعال رہے گا۔" logout_disabled: "جب تک سائٹ صرف پڑھنے کے مَوڈ میں ہے لاگ آؤٹ غیر فعال رہے گا۔" - too_few_topics_and_posts_notice: "چلیں اِس بحث کو شروع کریں! %{currentTopics} ٹاپکس اور %{currentPosts} پوسٹس موجود ہیں۔ زائرین کو پڑھنے اور اُن کا جواب دینے کیلئے مذید اور کی ضرورت ہے – ہم کم از کم %{requiredTopics} ٹاپکس اور %{requiredPosts} پوسٹس کی تجویز دیتے ہیں۔ صرف سٹاف اِس پیغام کو دیکھ سکتے ہیں۔" - too_few_topics_notice: "چلیں اِس بحث کو شروع کریں! %{currentTopics} ٹاپکس موجود ہیں۔ زائرین کو پڑھنے اور اُن کا جواب دینے کیلئے مذید اور کی ضرورت ہے – ہم کم از کم %{requiredTopics} ٹاپکس کی تجویز دیتے ہیں۔ صرف سٹاف اِس پیغام کو دیکھ سکتے ہیں۔" - too_few_posts_notice: "چلیں اِس بحث کو شروع کریں! %{currentPosts} پوسٹس موجود ہیں۔ زائرین کو پڑھنے اور اُن کا جواب دینے کیلئے مذید اور کی ضرورت ہے – ہم کم از کم %{requiredPosts} پوسٹس کی تجویز دیتے ہیں۔ صرف سٹاف اِس پیغام کو دیکھ سکتے ہیں۔" learn_more: "اورجانیے..." all_time: "کُل" all_time_desc: "کُل ٹاپک بنائے گئے" @@ -2526,6 +2523,7 @@ ur: help: "یہ ٹاپک غیر کسی فہرست میں نہیں ہے؛ یہ ٹاپکس کی فہرست میں ظاہر نہیں ہو گا، اور صرف ایک براہ راست لنک کے ذریعے اِس تک رسائی ہو سکے گی" personal_message: title: "یہ ٹاپک ایک ذاتی پیغام ہے" + help: "یہ ٹاپک ایک ذاتی پیغام ہے" posts: "پوسٹس" posts_long: "اِس ٹاپک میں {{number}} پوسٹس ہیں" posts_likes_MF: | diff --git a/config/locales/client.vi.yml b/config/locales/client.vi.yml index 173236d6fd..f69a16b7d1 100644 --- a/config/locales/client.vi.yml +++ b/config/locales/client.vi.yml @@ -1073,6 +1073,7 @@ vi: no_links: "Không có liên kết" most_liked_by: "Được thích nhiều nhất bởi" most_liked_users: "Like nhiều nhất" + no_likes: "Chưa có lượt thích." topics: "Chủ đề" replies: "Trả lời" ip_address: @@ -1381,6 +1382,7 @@ vi: posted: '{{username}} gửi bài trong "{{topic}}" - {{site_title}}' linked: '{{username}} liên quan đến bài viết của bạn từ "{{topic}}" - {{site_title}}' titles: + liked: "lượt thích mới" watching_first_post: "chủ đề mới" upload_selector: title: "Thêm một ảnh" @@ -1402,7 +1404,7 @@ vi: latest_post: "Bài viết mới nhất" latest_topic: "Chủ đề mới" most_viewed: "Xem nhiều nhất" - most_liked: "Like nhiều nhất" + most_liked: "Thích nhiều nhất" select_all: "Chọn tất cả" clear_all: "Xóa tất cả" too_short: "Từ khoá tìm kiếm của bạn quá ngắn." @@ -1797,7 +1799,7 @@ vi: controls: reply: "bắt đầu soản trả lời cho bài viết này" like: "like bài viết này" - has_liked: "bạn đã like bài viết này" + has_liked: "bạn đã thích bài viết này" undo_like: "hủy like" edit: "sửa bài viết này" edit_action: "Sửa" @@ -1834,6 +1836,10 @@ vi: notify_moderators: "đã thông báo với BQT" notify_user: "đã gửi tin nhắn" bookmark: "đã đánh dấu bài này" + like: + other: "thích này" + like_capped: + other: "và {{count}} người khác thích nầy" by_you: off_topic: "Bạn đã đánh dấu cái nfay là chủ đề đóng" spam: "Bạn đã đánh dấu cái này là rác" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index fa59219490..7ad3ead0be 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -1211,9 +1211,6 @@ zh_CN: enabled: "站点正处于只读模式。你可以继续浏览,但是回复、赞和其他操作暂时被禁用。" login_disabled: "只读模式下不允许登录。" logout_disabled: "站点在只读模式下无法登出。" - too_few_topics_and_posts_notice: "让我们开始讨论吧!现有%{currentTopics}个主题何%{currentPosts}个回帖。用户需要更多阅读与回复 —— 我们推荐至少%{requiredTopics}个主题和%{requiredPosts}个帖子。此消息仅管理人员可见。" - too_few_topics_notice: "让我们开始讨论吧!现在有%{currentTopics}个主题。 用户需要进行更多阅读与回复 – 我们推荐至少%{requiredTopics} 个主题。 此消息仅管理员可见。" - too_few_posts_notice: "让我们开始讨论吧!现在有%{currentPosts}个主题。 用户需要进行更多的阅读或回复 – 我们推荐至少%{requiredPosts} 个主题。 此消息仅管理人员可见。" logs_error_rate_notice: reached_hour_MF: "{relativeAge}{rate, plural, one {# error/hour} other {# errors/hour}}达到了站点设置中的限制{limit, plural, one {# error/hour} other {# errors/hour}}。" reached_minute_MF: "{relativeAge}1 – {rate, plural, one {# error/minute} other {# errors/minute}}已经达到站点设置限制 {limit, plural, one {# error/minute} other {# errors/minute}}。" @@ -2528,6 +2525,7 @@ zh_CN: help: "本主题被设置为不显示在主题列表中,只能通过链接来访问" personal_message: title: "此主题是一条私信" + help: "此主题是一条私信" posts: "帖子" posts_long: "本主题有 {{number}} 个帖子" posts_likes_MF: | diff --git a/config/locales/server.ar.yml b/config/locales/server.ar.yml index 587b124bc2..7c129f04f2 100644 --- a/config/locales/server.ar.yml +++ b/config/locales/server.ar.yml @@ -1086,7 +1086,6 @@ ar: desktop_category_page_style: "أسلوب العرض لصفحة الأقسام." category_colors: "قائمة الألوان المسموحة لتمييز الأقسام بترميز الhexadecimal." category_style: "أسلوب العرض لشارة القسم." - max_image_size_kb: "الحجم الاقص لتحميل صوره بالكيلو بايت.هذا يجب ضبطه في nginx (client_max_body_size) /اباتشي او البروكسي" max_attachment_size_kb: "أقصى حجم لتحميل المرفقات الملفات بالكيلوبايت. وهذا يجب أن يتم تكوينه في nginx (client_max_body_size) / أباتشي أو الوكيل. " authorized_extensions: "قائمة بالملفات المسموح رفعها (أستخدم '*' للسماح لجميع الأنواع)" max_similar_results: "عدد المواضيع المشابهة لتُعرض فوق المحرّر عند إنشاء موضوع جديد. المقارنة تعتمد عنوان الموضوع ومتنه." diff --git a/config/locales/server.be.yml b/config/locales/server.be.yml index 355eb61462..ddc531f97a 100644 --- a/config/locales/server.be.yml +++ b/config/locales/server.be.yml @@ -1161,10 +1161,8 @@ be: desktop_category_page_style: "Візуальны стыль для" category_colors: "Спіс шаснаццатковых значэнняў колеру дапускаецца для катэгорый." category_style: "Візуальны стыль для катэгорыі значкоў." - max_image_size_kb: "Максімальны памер загружанага выявы ў кбайт. Гэта павінна быць сканфігуравана ў Nginx (client_max_body_size)" theme_authorized_extensions: "Спіс пашырэнняў файлаў, дазволеных для загрузкі тэмы (выкарыстанне «*», каб ўключыць усе тыпы файлаў)" max_similar_results: "Як шмат падобных да тых, каб паказаць вышэй рэдактараў пры стварэнні новай тэмы. Параўнанне заснавана на назве і цела." - max_image_megapixels: "Максімальную колькасць мегапікселяў, дазволеныя для малюнка." title_prettify: "Прадухіліць агульныя назвы памылак друку і памылкі, у тым ліку вялікіх літар, малыя літары першага сімвал, шматразовы! і ?, за дадатковую плату. у канцы, і г.д." topic_views_heat_low: "Пасля гэтага шмат праглядаў, поле выгляд злёгку падсвятляецца." topic_views_heat_medium: "Пасля гэтага шмат праглядаў, поле праглядаў умерана падсвятляецца." diff --git a/config/locales/server.bg.yml b/config/locales/server.bg.yml index 934881ea2e..c835d6fdc6 100644 --- a/config/locales/server.bg.yml +++ b/config/locales/server.bg.yml @@ -174,6 +174,13 @@ bg: too_late_to_edit: "Това мнение е създадено много отдавна. То вече не може да се променя или да бъде изтрито." revert_version_same: "Текущата версия е същата като версията, към която се опитвате да се върнете." excerpt_image: "изображение" + bookmarks: + reminders: + later_today: "По-късно днес
{{date}}" + next_business_day: "Следващият работен ден
{{date}}" + tomorrow: "Утре
{{date}}" + next_week: "Следващата седмица
{{date}}" + next_month: "Следващият месец
{{date}}" groups: errors: invalid_domain: "'%{domain}' е невалиден домейн." @@ -459,6 +466,7 @@ bg: reports: default: labels: + count: Брой day: Ден post_edits: labels: @@ -469,6 +477,7 @@ bg: user_flagging_ratio: labels: user: Потребител + score: Точки moderators_activity: labels: moderator: Модератор @@ -802,7 +811,6 @@ bg: min_title_similar_length: "Минимална дължина на заглавието на темата, като тя ще бъде проверена за наличие на подобна." category_colors: "Списък от шестнадесетични цветови стойности разрешени за категориите." category_style: "Визуален стил за категорията със значки." - max_image_size_kb: "Максимален размер за качване на избражение в kB. Това също трябва да се конфигурира в nginx конфигурацията (client_max_body_size), apache или прокси сървъра." max_attachment_size_kb: "Максимална големина на прикачените файлове в kB. Това също трябва да се конфигурира в nginx (client_max_body_size), apache или прокси сървъра." authorized_extensions: "Списък от разширения на файлове разрешени за качване (използвайте '*' за да разрешите всички)" max_similar_results: "Брой подобни теми показвани на потребителя при създаването на нова тема. Сравнението е базирано на заглавието и текста на темата." @@ -1352,6 +1360,12 @@ bg: confirm_title: "Включени известявания - %{site_title}" confirm_body: "Успех! Известяването е включено." reviewables: + priorities: + medium: "Среден" + high: "Висок" + sensitivity: + medium: "Среден" + high: "Висок" actions: agree_and_suspend: title: "Преустанови потребител" diff --git a/config/locales/server.bs_BA.yml b/config/locales/server.bs_BA.yml index c382e4a5c1..1d8c0b4e2b 100644 --- a/config/locales/server.bs_BA.yml +++ b/config/locales/server.bs_BA.yml @@ -151,6 +151,15 @@ bs_BA: latest: "Latest topics" too_late_to_edit: "That post was created too long ago. It can no longer be edited or deleted." excerpt_image: "slika" + bookmarks: + reminders: + at_desktop: "Sljedeći put sam za svojim desktop kompjuterom" + later_today: "Danas, malo kasnije
{{date}}" + next_business_day: "Sljedeći radni dan
{{date}}" + tomorrow: "Sutradan
{{date}}" + next_week: "Sljedeće sedmice
{{date}}" + next_month: "Naredni mjesec
{{date}}" + custom: "Ciljano vrijeme i datum" groups: default_names: everyone: "everyone" @@ -499,12 +508,14 @@ bs_BA: http_5xx_reqs: xaxis: "Day" http_total_reqs: + title: "Suma" xaxis: "Day" time_to_first_response: xaxis: "Day" yaxis: "Prosječno vrijeme (hours)" topics_with_no_response: xaxis: "Day" + yaxis: "Suma" mobile_visits: xaxis: "Day" yaxis: "Number of visits" @@ -652,7 +663,6 @@ bs_BA: body_min_entropy: "The minimum entropy (unique characters, non-english count for more) required for a post body." min_title_similar_length: "The minimum length of a title before it will be checked for similar topics." category_colors: "A list of hexadecimal color values allowed for categories." - max_image_size_kb: "The maximum image upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well." max_attachment_size_kb: "The maximum attachment files upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well." authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)" max_similar_results: "How many similar topics to show above the editor when composing a new topic. Comparison is based on title and body." @@ -738,6 +748,11 @@ bs_BA: autoclosed_disabled: "This topic is now opened. New replies are allowed." autoclosed_disabled_lastpost: "Ova tema je sada otvorena. Novi postovi su dozvoljeni." login: + security_key_description: "Kada ste pripremili vaš fizikalni sigurnosni ključ (physical security key), pritisnite ispod dugme Prijava pomoću sigurnosnog ključa." + security_key_alternative: "Pokušaj na drugi način" + security_key_authenticate: "Prijava pomoću sigurnosnog ključa" + security_key_not_allowed_error: "Ovaj proces prijave pomoću sigurnosnog ključa je ili vremenski istekao ili je odkazan." + security_key_no_matching_credential_error: "Nisu pronađeni korisnički podatci koristeći navedeni sigurnosni ključ." not_approved: "Your account hasn't been approved yet. You will be notified by email when you are ready to log in." incorrect_username_email_or_password: "Netačan nadimak, email ili šifra" wait_approval: "Hvala vam što ste se prijavili. We will notify you when your account has been approved." @@ -941,6 +956,7 @@ bs_BA: title: "Oznake" finish_installation: register: + button: "Registriraj" help: "Registriraj novi račun kako bi počeo" resend_email: title: "Pošalji ponovo email aktivacije" diff --git a/config/locales/server.ca.yml b/config/locales/server.ca.yml index e9af238012..2cf54be443 100644 --- a/config/locales/server.ca.yml +++ b/config/locales/server.ca.yml @@ -1608,13 +1608,11 @@ ca: desktop_category_page_style: "Estil visual per a la pàgina /categories." category_colors: "Llista de valors de color hexadecimal permesos per a categories." category_style: "Estil visual per a insígnies de categoria." - max_image_size_kb: "Mida màxima de càrrega d'imatge en kB. Cal configurar-ho en nginx (client_max_body_size) / apache o en el proxy també." max_attachment_size_kb: "Mida màxima de càrrega de fitxers adjunts en kB. Cal configurar-ho en nginx (client_max_body_size) / apache o en el proxy també." authorized_extensions: "Llista d'extensions de fitxer permeses per a carregar (feu servir '*' per a habilitar tota mena de fitxers)" authorized_extensions_for_staff: "Llista d'extensions permeses als usuaris de l'equip responsable en carregar fitxers a més de la llista definida en el paràmetre `authorized_extensions` de la configuració. (Feu servir \"*\" per a habilitar tots els tipus de fitxers.)" theme_authorized_extensions: "Llista d'extensions de fitxers permeses per a càrregues d'aparences (utilitzeu '*' per a permetre tots els tipus de fitxers)" max_similar_results: "Quants temes semblants es mostren per damunt de l'editor quan es redacta un tema nou. La comparació es basa en el títol i el cos." - max_image_megapixels: "Nombre màxim de megapíxels permesos en una imatge." title_prettify: "Evita errades tipogràfiques freqüents en el títol, incloent-hi tot en majúscula, primer caràcter en minúscula, exclamacions i interrogants múltiples, punts extres al final, etc." title_remove_extraneous_space: "Elimina els espais blancs de davant de la puntuació final." automatic_topic_heat_values: 'Actualitza automàticament els paràmetres de "topic views heat" i "topic post like heat" basant-se en l''activitat del lloc web. ' diff --git a/config/locales/server.de.yml b/config/locales/server.de.yml index 23d4e29b32..e463bdcec1 100644 --- a/config/locales/server.de.yml +++ b/config/locales/server.de.yml @@ -1625,13 +1625,11 @@ de: desktop_category_page_style: "Visueller Stil für die /categories Seite" category_colors: "Liste hexadezimaler Farbwerte, die als Kategoriefarben erlaubt sind." category_style: "Visueller Stil für Kategorie-Abzeichen." - max_image_size_kb: "Maximale Größe eines hochgeladenen Bilds in kB. Dieser Wert muss auch in Nginx (client_max_body_size), Apache oder anderen Proxies entsprechend konfiguriert werden." max_attachment_size_kb: "Maximale Größe hochgeladener Dateianhänge in kB. Dieser Wert muss auch in Nginx (client_max_body_size), Apache oder anderen Proxies entsprechend konfiguriert werden." authorized_extensions: "Liste von erlaubten Dateiendungen für hochgeladene Dateien ('*' um alle Dateiendungen zu erlauben)" authorized_extensions_for_staff: "Eine Liste von erlaubten Dateiendungen für den Upload von Dateien durch Team-Benutzer, zusätzlich zu der in der Seiteninstellung `authorized_extensions` definierten Liste. (Der Wert „*“ erlaubt alle Dateitypen.)" theme_authorized_extensions: "Liste von erlaubten Dateiendungen für hochgeladene Themes (verwende '*', um alle Dateitypen zu erlauben)" max_similar_results: "Anzahl ähnlicher Themen, die beim Erstellen eines neuen Themas über dem Editor angezeigt werden. Ähnlichkeit wird an Hand des Titels und Inhalts bestimmt." - max_image_megapixels: "Maximale erlaubte Auflösung für Bilder (in Megapixeln)." title_prettify: "Verhindert gängige Fehler im Titel, wie reine Grossschreibung, Kleinbuchstaben am Anfang, mehrere ! und ?, überflüssiger . am Ende, etc." title_remove_extraneous_space: "Entferne führende Leerzeichen vor dem Ende-Zeichen." automatic_topic_heat_values: 'Update die "Themenansicht-Erhitzung" und "Themenbeitrags ''Gefällt mir'' Erhitzung" Einstellungen automatisch basierend auf der Seiten-Aktivität.' @@ -1856,7 +1854,7 @@ de: default_categories_tracking: "Liste der standardmäßig gefolgten Kategorien." default_categories_muted: "Liste der standardmäßig stummgeschalteten Kategorien." default_categories_watching_first_post: "Liste von Kategorien, in denen der erste Beiträge in jedem neuen Thema automatisch beobachtet wird." - mute_all_categories_by_default: "Setze die Standard E-Mail Benachrichtigungs-Stufe für alle Kategorien auf stummgeschaltet. Benötigt die Zustimmung der Benutzer, damit sie in \"neueste\" und Kategorien-Seiten erscheinen. Um den Standard für anonyme Benutzer anzupassen, müssem 'default_categories_' Einstellungen gesetzt werden." + mute_all_categories_by_default: "Setze die Standard E-Mail Benachrichtigungs-Stufe für alle Kategorien auf stummgeschaltet. Benötigt die Zustimmung der Benutzer, damit sie in \"neueste\" und Kategorien-Seiten erscheinen. Um den Standard für anonyme Benutzer anzupassen, müssen 'default_categories_' Einstellungen gesetzt werden." default_tags_watching: "Liste der Tags, die standardmäßig beobachtet werden." default_tags_tracking: "Liste der Tags, die standardmäßig verfolgt werden." default_tags_muted: "Liste der Tags, die standardmäßig stummgeschaltet werden." @@ -3036,9 +3034,19 @@ de: confirm_new_email: title: "E-Mail-Adresse bestätigen (an neue)" subject_template: "[%{email_prefix}] Bestätige deine neue E-Mail-Adresse" + text_body_template: | + Bestätige bitte deine neue E-Mail Adresse für %{site_name} durch einen Klick auf den folgenden Link: + + %{base_url}/u/confirm-new-email/%{email_token} confirm_old_email: title: "E-Mail-Adresse bestätigen (an alte)" subject_template: "[%{email_prefix}] Bestätige deine aktuelle E-Mail-Adresse" + text_body_template: | + Bevor wir die E-Mail Adresse ändern können, benötigen wir deine Bestätigung, dass du den aktuellen E-Mail Account kontrollierst. Sobald du das getan hast, schicken wir dir eine Anfrage, die neue E-Mail Adresse zu bestätigen. + + Bestätige deine aktuelle E-Mail Adresse für %{site_name}, indem du auf den folgenden Link klickst: + + %{base_url}/u/confirm-old-email/%{email_token} notify_old_email: title: "Benachrichtigung an alte E-Mail-Adresse" subject_template: "[%{email_prefix}] Deine E-Mail-Adresse wurde geändert" diff --git a/config/locales/server.el.yml b/config/locales/server.el.yml index 41f1446c85..8263d27680 100644 --- a/config/locales/server.el.yml +++ b/config/locales/server.el.yml @@ -1065,12 +1065,10 @@ el: desktop_category_page_style: "Οπτικό στυλ για τη σελίδα /Categories." category_colors: "Μια λίστα με τιμές δεκαεξαδικού χρώματος, που επιτρέπεται για τις κατηγορίες." category_style: "Οπτικό στυλ για τα εμβλημάτα κατηγορίας ." - max_image_size_kb: "Το μέγιστο μέγεθος εικόνας για μεταφόρτωση σε kB. Αυτό πρέπει να ρυθμιστεί στο nginx (client_max_body_size) / apache ή και στο proxy." max_attachment_size_kb: "Το μέγιστο μέγεθος συννημένων αρχείων για μεταφόρτωση σε kB. Αυτό πρέπει να ρυθμιστεί στο nginx (client_max_body_size) / apache ή και στο proxy." authorized_extensions: "Μια λίστα με επεκτάσεις αρχείου οι οποιες επιτρέπονται για ανέβασμα (use '*' to enable all file types)" theme_authorized_extensions: "Μια λίστα από επεκτάσεις οι οποίες επιτρέπονται για τις μεταφορτώσεις θεμάτων ('*' για ενεργοποίηση όλων των τύπων αρχείων)" max_similar_results: "Πόσα παρόμοια νήματα να εμφανίζονται πάνω από τον εκδότη, όταν δημιουργείς ένα νέο νήμα. Η σύγκριση βασίζεται στον τίτλο και το σώμα." - max_image_megapixels: "Ο μέγιστος αριθμός megapixel που επιτρέπεται σε μία εικόνα. " title_prettify: "Απέφυγε συνηθισμένα τυπογραφικά λάθη στους τίτλους, όπως όλα τα γράμματα να είναι κεφαλαία, το πρώτο γράμμα της λέξης να είναι μικρό, πολλαπλά ! και ;, επιπλέον . στο τελος, κτλ. " topic_views_heat_low: "Μετά από τόσες προβολές, το πεδίο των προβολών είναι ελάχιστα τονισμένο. " topic_views_heat_medium: "Μετά από τόσες προβολές, το πεδίο των προβολών είναι μέτρια τονισμένο. " diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index b6df9f32bc..a8d10b3571 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -223,7 +223,7 @@ es: request_membership: "Solicitar membresía" join_group: "Unirse al grupo" deleted_topic: "¡Ups! Este tema se ha eliminado y ya no está disponible." - delete_topic_failed: "Se produjo un error al borrar el tema. Por favor, contacta al administrador del sitio." + delete_topic_failed: "Se ha producido un error al borrar el tema. Por favor, contacta al administrador del sitio." reading_time: "Tiempo de lectura" likes: "Me gusta" too_many_replies: @@ -1645,13 +1645,11 @@ es: desktop_category_page_style: "Estilo visual de la página de /categorías." category_colors: "Una lista de valores en hexadecimal de los colores para las categorías." category_style: "Estilo visual de las etiquetas de categoría." - max_image_size_kb: "El tamaño máximo, en kB, de las imágenes que se pueden subir. Debe ser configurado también en nginx (client_max_body_size) / apache o proxy." max_attachment_size_kb: "El tamaño máximo, en kB, de los archivos que se pueden adjuntar. Debe ser configurado también en nginx (client_max_body_size) / apache o proxy." authorized_extensions: "Una lista de las extensiones de archivo que se permite subir (usa «*» para habilitar todos los tipos de archivo)" authorized_extensions_for_staff: "Una lista de las extensiones de archivo que se le permite subir a miembros del staff sumada a la lista definida en la configuración `authorized_extensions`. (Usa «*» para habilitar todos los tipos)" theme_authorized_extensions: "Una lista de las extensiones de archivo que se permite subir (usa «*» para habilitar todos los tipos)" max_similar_results: "Cantidad de temas similares que se muestran encima del editor cuando se está creando un nuevo tema. La comparación se basa en el título y el cuerpo del tema." - max_image_megapixels: "Número máximo de megapíxeles permitidos en una imagen." title_prettify: "Prevenir errores comunes en el título, incluidos los títulos escritos todo mayúsculas, con la primera letra en minúscula, con múltiples signos ! o ?, . adicional al final, etc." title_remove_extraneous_space: "Eliminar los espacios en blanco delante de la puntuación final." automatic_topic_heat_values: 'Actualizar automáticamente la configuración de «temperatura de vistas del tema» y «temperatura de me gusta de publicaciones del tema» según la actividad del sitio.' diff --git a/config/locales/server.fa_IR.yml b/config/locales/server.fa_IR.yml index be10625aab..fec91a39a9 100644 --- a/config/locales/server.fa_IR.yml +++ b/config/locales/server.fa_IR.yml @@ -219,6 +219,15 @@ fa_IR: too_late_to_edit: "آن فرسته خیلی وقت پیش ساخته شده. دیگر امکان ویرایش یا حذف آن وجود ندارد." revert_version_same: "نسخه فعلی همان نسخه‌ای است که می‌خواهید به آن برگردید." excerpt_image: "تصویر" + bookmarks: + reminders: + at_desktop: "بار آینده من پشت میزم هستم" + later_today: "امروز کمی بعد
{{date}}" + next_business_day: "روز کاری آینده
{{date}}" + tomorrow: "فردا
{{date}}" + next_week: "هفته ی آینده
{{date}}" + next_month: "ماه آینده
{{date}}" + custom: "درج تاریخ و ساعت" groups: errors: can_not_modify_automatic: "نمی‌توانید گروه‌های خودکار را تغییر دهید." @@ -1048,12 +1057,10 @@ fa_IR: desktop_category_page_style: "سبک بصری برای صفحه‌ی دسته‌بندی" category_colors: "لیست مقادیر رنگ هگزا دسیمال مجاز برای دسته‌بندی‌ها." category_style: "سبک بصری برای نشان دسته‌بندی" - max_image_size_kb: "حداکثر سایز عکس بارگزاری شده با واحد کیلوبایت. این باید در پیکربندی nginx باشد (client_max_body_size) / همچنین apache یا proxy." max_attachment_size_kb: "حداکثر سایز فایل پیوست شده به واحد کیلوبایت. این باید در پیکربندی nginx باشد (client_max_body_size) / همچنین apache یا proxy." authorized_extensions: "لیست پسوند‌های مجاز فایل برای بارگذاری ( از '*' برای اجازه به تمام فایل‌ها استفاده کنید)" theme_authorized_extensions: "لیست پسوند‌های قابل بارگذاری برای قالب (از '*' برای اجازه به تمامی فایل‌ها استفاده کنید)" max_similar_results: "چند موضوع مشابه زیر ویرایشگر وقتی که موضوع جدید ایجاد می شود، نمایش داده شود. مقایسه بر اساس عنوان و متن است. " - max_image_megapixels: "حداکثر اندازه تصاویر با واحد مگاپیکسل." title_prettify: "از غلط های املایی و اشتباهات رایج جلوگیری کن٬ از جمله همه حروف بزرگ٬‌ حرف کوچک اولین کاراکتر، ! و ؟ چندگانه . اضافه در پایان و غیره." topic_views_heat_low: "بعد از این تعداد بازدید، فیلد تعداد بازدید بسیار پر‌رنگ می‌شود." topic_views_heat_medium: "بعد از این تعداد بازدید، فیلد تعداد بازدید پر‌رنگ می‌شود." diff --git a/config/locales/server.fi.yml b/config/locales/server.fi.yml index 41032c4de6..cc70ad1c0b 100644 --- a/config/locales/server.fi.yml +++ b/config/locales/server.fi.yml @@ -1635,13 +1635,11 @@ fi: desktop_category_page_style: "/Keskustelualueet-sivun visuaalinen tyyli." category_colors: "Lista alueiden sallituista väriarvoista, heksadesimaaleina." category_style: "Aluemerkin tyyli." - max_image_size_kb: "Liitetyn kuvan suurin sallittu koko kilotavuissa. Tämä pitää asettaa myös nginxin (client_max_body_size) / apachen tai proxyn asetuksista." max_attachment_size_kb: "Liitetyn tiedoston suurin sallittu koko kilotavuissa. Tämä pitää asettaa myös nginxin (client_max_body_size) / apachen tai proxyn asetuksista." authorized_extensions: "Liitetiedostojen sallitut tiedostopäätteet (käytä '*' salliaksesi kaikki tiedostotyypit)" authorized_extensions_for_staff: "Luettelo tiedostopäätteistä, jotka ovat sallittuja henkilökunnan jäsenille niiden lisäksi, jotka on määritelty sivustoasetuksella \"authorized_extensions\". (salli asettamalla * kaikki tiedostotyypit)" theme_authorized_extensions: "Teemalatausten liitetiedostojen sallitut tiedostopäätteet (käytä '*' salliaksesi kaikki tiedostotyypit)" max_similar_results: "Kuinka monta samankaltaista ketjua näytetään viestikentän päällä uutta ketjua aloitettaessa. Vertailu perustuu sekä otsikkoon että leipätekstiin." - max_image_megapixels: "Kuvan enimmäiskoko megapikseleinä." title_prettify: "Estä yleiset kirjoitusvirheet otsikossa, kuten pelkät isot kirjaimet, pieni ensimmäinen kirjain, useat !- ja ?-merkit ym." title_remove_extraneous_space: "Poista lopettavia välimerkkejä edeltävät tyhjät merkit." automatic_topic_heat_values: 'Päivitä "topic views heat" ja "topic post like heat" -asetuksia sivuston aktiivisuuden perusteella automaattisesti.' diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index ed0ecfc0ea..ed4897d43e 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -1617,13 +1617,11 @@ fr: desktop_category_page_style: "Style visuel de la page /categories." category_colors: "Une liste de couleurs en hexadécimale autorisées pour les catégories." category_style: "Style visuel pour les badges de catégorie." - max_image_size_kb: "La taille maximale des images en Ko. Doit être configuré dans nginx (client_max_body_size) / apache ou proxy aussi." max_attachment_size_kb: "La taille maximale des fichiers envoyés en Ko. Doit être configurer dans nginx (client_max_body_size) / apache ou proxy aussi." authorized_extensions: "Une liste d'extensions de fichier autorisées pour les envois sur le serveur (mettre '*' pour autoriser tous les types)" authorized_extensions_for_staff: "Une liste des extensions de fichiers autorisées pour le téléchargement pour les responsables en plus de la liste définie dans le paramètre `authorized_extensions'. (utilisez '*' pour activer tous les types de fichiers)" theme_authorized_extensions: "Une liste d'extensions de fichier autorisées pour les envois de thème (mettre « * » pour autoriser tous les types de fichier)" max_similar_results: "Combien de sujets similaires sont afficher lorsqu'un utilisateur est en train de créer un nouveau sujet. La comparaison se base sur le titre et le contenu." - max_image_megapixels: "Nombre maximum autorisé de mégapixels pour une image." title_prettify: "Corrige les coquilles les plus communes dans les titres (intégralité du titre en majuscule, première lettre en minuscule, de multiples ! et ?, un . inutile à la fin, etc.)" title_remove_extraneous_space: "Supprimez les espaces devant les signes de ponctuation de fin." automatic_topic_heat_values: 'Mettez à jour automatiquement les paramètres "Sujet affiché" et "Sujet similaire" en fonction de l''activité du site.' diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index 3b1fe8298c..7d39b64201 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -1141,6 +1141,7 @@ he: labels: level: דרגה description: "מספר המשתמשים בקיבוץ לפי דרגת אמון." + description_link: "https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/" users_by_type: title: "משתמשים לפי סוג" xaxis: "סוג" @@ -3715,7 +3716,7 @@ he: name: ברוכים הבאים description: קיבלו לייק long_description: | - עיטור זוה מוענק עם קבלת הלייק הראשון שלך על פוסט. מזל טוב, פרסמת משהו שחבריך לקהילה חשבו שהוא מעניין, מגניב, או שימושי! + עיטור זה מוענק עם קבלת הלייק הראשון שלך על פוסט. מזל טוב, פרסמת משהו שחבריך לקהילה חשבו שהוא מעניין, מגניב, או שימושי! autobiographer: name: אוטוביוגרפים description: "פרטי הפרופיל הושלמו" diff --git a/config/locales/server.hy.yml b/config/locales/server.hy.yml index b8e1e33ac1..661caa18a8 100644 --- a/config/locales/server.hy.yml +++ b/config/locales/server.hy.yml @@ -1428,13 +1428,11 @@ hy: desktop_category_page_style: "Արտաքին ոճ /կատեգորիաներ էջի համար:" category_colors: "Կատեգորիաների համար թույլատրելի գույների տանսվեցերորդական արժեքների ցանկ:" category_style: "Կատեգորիայի կրծքանշանների համար արտաքին ոճը:" - max_image_size_kb: "Նկարի վերբեռնման առավելագույն չափը կԲ-ով: Սա պետք է կարգավորվի nginx (client_max_body_size) / apache կամ proxy -ում:" max_attachment_size_kb: "Կցված ֆայլերի վերբեռնման առավելագույն չափը կԲ-երով: Սա պետք էկլարգավորվի nginx-ում (client_max_body_size) / apache -ում, ինչպես նաև՝ proxy -ում:" authorized_extensions: "Վերբեռնման համար թույլատրելի ֆայլերի ընդլայնումների ցանկը (օգտագործեք '*' ֆայլերի բոլոր տիպերը միացնելու համար)" authorized_extensions_for_staff: "Ֆայլերի ընդլայնումների ցանկ, որոնք թույլատրելի են վերբեռնման համար անձնակազմի անդամ օգտատերերի համար, ի հավելումն `authorized_extensions` կայքի կարգավորման մեջ սահմանված ցանկի: (օգտագործեք '*' ֆայլերի բոլոր տիպերը միացնելու համար)" theme_authorized_extensions: "Թեմայի վերբեռնումների համար թույլատրելի ֆայլերի ընդլայնումների ցանկ (օգտագործեք '*' բոլոր ֆայլերի տիպերը միացնելու համար)" max_similar_results: "Քանի նման թեմաներ ցուցադրել խմբագրիչի վերևում՝ նոր թեմա ստեղծելիս: Համեմատությունը հիմնված է վերնագրի և տեքստի վրա:" - max_image_megapixels: "Նկարի համար թույլատրելի մեգապիկսելների առավելագույն քանակը:" title_prettify: "Արգելել սովորական վերնագրի վրիպակները և սխալները՝ ներառյալ բոլոր մեծատառերը, առաջին սիմվոլի փոքրատառ լինելը, բազմակի ! և ? , լրացուցիչ . վերջում և այլն:" topic_views_heat_low: "Այս քանակի դիտումներից հետո դիտումների դաշտը թեթևակի ընդգծվում է:" topic_views_heat_medium: "Այս քանակի դիտումներից հետո դիտումների դաշտը չափավոր ընդգծվում է:" diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index e907c54035..bb53cb61cb 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -49,6 +49,7 @@ it: about_json_values: "about.json contiene valori non validi: %{errors}" git: "Errore nella clonazione del repository git, accesso negato o repository non trovato" unpack_failed: "Errore estranedo il contenuto del file" + file_too_big: "Il file non compresso è troppo grande." unknown_file_type: "Il file che hai caricato non sembra essere un tema di Discourse valido." errors: component_no_user_selectable: "I componenti del tema non possono essere selezionabili dall'utente" @@ -208,6 +209,7 @@ it: email_template_cant_be_modified: "Questo modello di email non può essere modificato." invalid_whisper_access: "I Sussurri potrebbero non essere abilitati, oppure non hai il permesso di creare Messaggi Sussurri." not_in_group: + title_topic: "Devi essere membro di un gruppo per visualizzare questa argomento." join_group: "Partecipa al Gruppo" reading_time: "Tempo di lettura" likes: "Mi piace" @@ -236,7 +238,9 @@ it: replies: one: "%{count} risposta" other: "%{count} risposte" + last_reply: "Ultima risposta" created: "Creazione" + new_topic: "Inizia un nuovo argomento" no_mentions_allowed: "Spiacenti, non puoi menzionare altri utenti." too_many_mentions: one: "Spiacenti, puoi menzionare al massimo un utente in un messaggio." @@ -304,6 +308,17 @@ it: edit_conflict: "Il messaggio è stato modificato da un altro utente e i tuoi cambiamenti non possono essere salvati." revert_version_same: "La versione attuale è la stessa versione che stai cercando di ripristinare." excerpt_image: "immagine" + bookmarks: + errors: + already_bookmarked_post: "Non puoi aggiungere più di un segnalibro allo stesso messaggio." + reminders: + at_desktop: "La prossima volta che sarò al mio desktop" + later_today: "Più tardi, oggi
{{date}}" + next_business_day: "Il prossimo giorno lavorativo
{{date}}" + tomorrow: "Domani
{{date}}" + next_week: "La prossima settimana
{{date}}" + next_month: "Il prossimo mese
{{date}}" + custom: "Data e ora personalizzate" groups: success: bulk_add: @@ -694,6 +709,9 @@ it: error: "Si è verificato un errore durante la modifica del tuo indirizzo email. Forse l'indirizzo è già in uso?" error_staged: "Si è verificato un errore durante il cambio di indirizzo email. L'indirizzo è già stato usato da un utente temporaneo." already_done: "Spiacenti, il collegamento di conferma non è più valido. Hai forse già cambiato email?" + confirm: "Conferma" + authorizing_new: + title: "Conferma il tuo nuovo indirizzo email" associated_accounts: revoke_failed: "Impossibile revocare il tuo account con %{provider_name}." connected: "(connesso)" @@ -1542,13 +1560,11 @@ it: desktop_category_page_style: "Stile visuale per la pagina /categorie." category_colors: "Un elenco di valori esadecimali di colori permessi per le categorie." category_style: "Stile grafico dei distintivi relativi alle categorie." - max_image_size_kb: "Dimensione massima in kB per caricare immagini degli utenti. Deve essere configurata anche in nginx (client_max_body_size) / apache o nel proxy." max_attachment_size_kb: "Dimensione massima dei file che gli utenti possono caricare, in kB. Configura il limite anche in nginx (client_max_body_size) / apache o nel proxy." authorized_extensions: "Una lista di estensioni dei file che è permesso caricare (usa '*' per permettere tutti i tipi di file) " authorized_extensions_for_staff: "Un elenco di estensioni di file consentite per il caricamento da parte dello staff in aggiunta all'elenco definito nell'impostazione del sito `authorized_extensions`. (usa '*'; per abilitare tutti i tipi di file)" theme_authorized_extensions: "Una lista di estensioni dei file permessi per i caricamenti dei temi (usa '*' per abilitare tutti i tipi di file)" max_similar_results: "Quanti argomenti simili mostrare sopra l'editor quando si scrive un nuovo argomento. Il paragone viene fatto sul titolo e sul corpo." - max_image_megapixels: "Massimo numero di megapixel consentito per un'immagine." title_prettify: "Evita refusi ed errori comuni nei titoli, incluso il testo tutto maiuscolo, il primo carattere minuscolo, troppi caratteri ! e ?, puntini aggiuntivi alla fine della parola ecc." title_remove_extraneous_space: "Rimuovi gli spazi bianchi davanti alla punteggiatura." automatic_topic_heat_values: 'Aggiorna automaticamente le impostazioni "topic views heat" e "topic post like heat" in base all''attività del sito.' diff --git a/config/locales/server.ja.yml b/config/locales/server.ja.yml index 0b29e4d7ad..8224b63b54 100644 --- a/config/locales/server.ja.yml +++ b/config/locales/server.ja.yml @@ -914,7 +914,6 @@ ja: min_title_similar_length: "類似トピックのチェックに必要な最小タイトル長" category_colors: "カテゴリに利用可能な色 (16進数指定) のリスト" category_style: "カテゴリバッジのスタイル" - max_image_size_kb: "アップロード可能な画像の最大サイズ (kB) nginx 側での設定 (client_max_body_size) / apache または proxy における設定も同時に行う必要があります" max_attachment_size_kb: "添付可能なファイルの最大サイズ (kB) nginx 側での設定 (client_max_body_size) / apache または proxy における設定も同時に行う必要があります" authorized_extensions: "アップロード可能なファイルの拡張子のリスト('*'で全ての拡張子が有効になります)" max_similar_results: "新規トピック編集中に類似トピックをいくつ表示するか。比較はタイトルと本文に基づきます" diff --git a/config/locales/server.ko.yml b/config/locales/server.ko.yml index cc17fc67af..e7eeba1664 100644 --- a/config/locales/server.ko.yml +++ b/config/locales/server.ko.yml @@ -1112,12 +1112,10 @@ ko: desktop_category_page_style: "/categories 페이지의 비주얼 스타일" category_colors: "허용된 카테고리에 사용될 hexadecimal 색상 값의 리스트" category_style: "카테고리 뱃지 시각 스타일" - max_image_size_kb: "최대 이미지 업로드 사이즈(kB). 이 설정은 꼭 nginx / apache와 proxy에도 적용해야 합니다." max_attachment_size_kb: "최대 첨부파일 업로드 사이즈(kB). 이 설정은 꼭 nginx / apache와 proxy에도 적용해야 합니다." authorized_extensions: "파일 업로드에 허용되는 확장자 리스트 ('*'을 사용하면 모든 타입의 파일이 가능합니다.)" theme_authorized_extensions: "테마 업로드에 허용되는 확장자 목록('*'를 입력하면 모든 확장자 허용)" max_similar_results: "새로운 글타래를 작성할 때, 에디터 위에 보여줄 비슷한 글타래들의 개수. 제목과 본문을 바탕으로 비교합니다." - max_image_megapixels: "이미지의 최대 메가픽셀수" title_prettify: "일반적인 제목의 오타 및 오류를 수정해준다. 모두 대문자로 쓰거나, 첫자가 소문자이거나(영문), 복수의 !, ? 혹은 마침표(.)가 중복으로 들어간 것 등" topic_views_heat_low: "글타래가 연하게 하이라이트 되기 위한 조회수" topic_views_heat_medium: "글타래가 적당하게 하이라이트 되기 위한 조회수" diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index 9c775f66e6..adebe50938 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -1073,6 +1073,7 @@ nl: labels: level: Niveau description: "Aantal gebruikers gegroepeerd op vertrouwensniveau." + description_link: "https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/" users_by_type: title: "Gebruikers per type" xaxis: "Type" diff --git a/config/locales/server.pl_PL.yml b/config/locales/server.pl_PL.yml index 8a94e48fad..3e43f69002 100644 --- a/config/locales/server.pl_PL.yml +++ b/config/locales/server.pl_PL.yml @@ -1450,12 +1450,10 @@ pl_PL: desktop_category_page_style: "Styl wizualny dla strony kategorii." category_colors: "Lista kolorów w formacie hex do użycia w etykietach kategorii." category_style: "Styl etykiet kategorii" - max_image_size_kb: "Maksymalny rozmiar wgrywanego pliku graficznego w kB. Należy to także skonfigurować dla serwera nginx (client_max_body_size) / Apache lub dla proxy." max_attachment_size_kb: "Maksymalny rozmiar załącznika w kB. Należy to także skonfigurować dla serwera nginx (client_max_body_size) / Apache lub dla proxy." authorized_extensions: "Lista dozwolonych rozszerzeń plików (gwiazdka \"*\" oznacza wszystkie typy plików)" theme_authorized_extensions: "Lista dozwolonych rozszerzeń plików dla przesyłania szablonów (gwiazdka \"*\" oznacza wszystkie typy plików)" max_similar_results: "Liczba podobnych wątków, jaka zostanie wyświetlona nad oknem edytora podczas tworzenia nowego wątku. Wątki są porównywane na podstawie tytułów i treści." - max_image_megapixels: "Maksymalna rozdzielczość pliku graficznego w megapikselach." title_prettify: "Prevent common title typos and errors, including all caps, lowercase first character, multiple ! and ?, extra . at end, etc." topic_views_heat_low: "Po tylu wyświetleniach liczba wyświetleń zostanie lekko wyróżniona." topic_views_heat_medium: "Po tylu wyświetleniach liczba wyświetleń zostanie wyróżniona." diff --git a/config/locales/server.pt.yml b/config/locales/server.pt.yml index b0c3546265..069248ad52 100644 --- a/config/locales/server.pt.yml +++ b/config/locales/server.pt.yml @@ -1036,7 +1036,6 @@ pt: desktop_category_page_style: "Estilo visual para a página de categorias." category_colors: "Lista de valores hexadecimais das cores permitidas nas categorias." category_style: "Estilo visível para distintivos de categorias." - max_image_size_kb: "Tamanho máximo da imagem carregada em kB. Este deverá ser configurado em nginx (client_max_body_size) / apache ou também proxy." max_attachment_size_kb: "Tamanho máximo dos anexos carregados em kB. Este deverá ser configurado em nginx (client_max_body_size) / apache ou também proxy." authorized_extensions: "Lista de extensões permitidas para carregamento (utilizar '*' para ativar todos os tipos de ficheiros)" max_similar_results: "Quantos tópicos semelhantes a serem exibidos acima do editor ao compor um novo tópico. A comparação é baseada no título e no corpo." diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index c69c1982c9..34f2e9b252 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -1584,13 +1584,11 @@ pt_BR: desktop_category_page_style: "Estilo visual para a página / categorias." category_colors: "Uma lista de valores hexadecimais de cor permitidos para categorias." category_style: "Estilo visual para emblemas de categoria." - max_image_size_kb: "O tamanho máximo de upload de imagem em kB. Isso precisa ser configurado no nginx (client_max_body_size) / apache ou também proxy." max_attachment_size_kb: "O tamanho máximo de upload de arquivos anexos em kB. Isso precisa ser configurado no nginx (client_max_body_size) / apache ou também proxy." authorized_extensions: "Uma lista de extensões de arquivo permitidas para upload (use '*' para permitir todos os tipos de arquivos)" authorized_extensions_for_staff: "Uma lista de extensões de arquivo permitidas para upload para usuários da equipe, além da lista definida na configuração do site `authorized_extensions`. (use '*' para ativar todos os tipos de arquivo)" theme_authorized_extensions: "Uma lista de extensões de arquivo permitidas para uploads de temas (use '*' para ativar todos os tipos de arquivos)" max_similar_results: "Quantos tópicos semelhantes exibir acima do editor quando compondo um novo tópico. A comparação é baseada no título e no corpo." - max_image_megapixels: "Número máximo de megapixels permitidos em uma imagem." title_prettify: "Prevenir erros comuns em títulos, incluindo caps-lock ligado, primeira letra minúscula, excesso de ! e ?, pontos extras no final, etc." title_remove_extraneous_space: "Remover os espaços em branco iniciais à frente da pontuação final." automatic_topic_heat_values: 'Atualizar automaticamente as configurações "visualizações de tópico populares" e "curtidas de postagens de tópicos populares" com base na atividade do site.' diff --git a/config/locales/server.ro.yml b/config/locales/server.ro.yml index 1b8f5186ec..9026cd79c8 100644 --- a/config/locales/server.ro.yml +++ b/config/locales/server.ro.yml @@ -993,7 +993,6 @@ ro: desktop_category_page_style: "Stil vizual pentru pagina /categories ." category_colors: "O listă hexazecimală de valori de culori permise pentru categorii." category_style: "Stil vizual pentru categoria ecusoane." - max_image_size_kb: "Mărimea maximă a unei imagini încărcate în kB. Aceasta trebuie configurată în nginx (client_max_body_size) / apache sau proxy." max_attachment_size_kb: "Mărimea maximă a unui atașament de fișiere încărcate în Kb. Aceasta trebuie configurata în nginx (client_max_body_size) / apache sau proxy." authorized_extensions: "O listă de extensii de fișiere permise la încărcare (folosiți '*' pentru activarea tuturor tipurilor de fișiere)" max_similar_results: "Câte subiecte similare vor fi afișate deasupra editorului atunci când se compune un subiect nou. Comparația se face după titlu și pe conținut." diff --git a/config/locales/server.ru.yml b/config/locales/server.ru.yml index 836ad7403f..6699cf541d 100644 --- a/config/locales/server.ru.yml +++ b/config/locales/server.ru.yml @@ -1524,11 +1524,9 @@ ru: desktop_category_page_style: "Визуальный стиль для страницы категории." category_colors: "Список шестнадцатеричных кодов цветов, разрешенных для разделов." category_style: "Стили для выделения разделов." - max_image_size_kb: "Максимальный размер загружаемых картинок в килобайтах. Убедитесь, что вы также настроили ограничение в nginx (client_max_body_size) / apache или прокси." max_attachment_size_kb: "Максимальный размер загружаемых файлов в килобайтах. Убедитесь, что вы также настроили ограничение в nginx (client_max_body_size) / apache или прокси." authorized_extensions: "Список расширений файлов, разрешенных к загрузке. Используйте '*', чтобы разрешить любые типы файлов." max_similar_results: "Количество похожих тем, показываемых пользователю во время создания новой темы. Сравнение выполняется на основании названия и текста темы." - max_image_megapixels: "Максимально допустимое количество мегапикселей для изображения." title_prettify: "Предотвращать распространенные опечатки и ошибки, включая КАПС, первый строчный символ, множественные ! и ?, лишние . в конце предложения и т.д." title_remove_extraneous_space: "Удалите начальные пробелы перед конечной пунктуацией." topic_views_heat_low: "После этого количества просмотров, поле просмотров слегка подсвечивается." diff --git a/config/locales/server.sk.yml b/config/locales/server.sk.yml index d7dde1eb51..d530c26d6c 100644 --- a/config/locales/server.sk.yml +++ b/config/locales/server.sk.yml @@ -943,7 +943,6 @@ sk: min_title_similar_length: "Minimálna dĺžka nadpisu na spustenie kontroly na podobné témy." category_colors: "Zoznam hexadecimálnych hodnôt farieb povolených pre kategórie." category_style: "Vizuálny štýl pre odznaky za kategórie." - max_image_size_kb: "Mmaximálna veľkosť vloženého obrázku v kB. Rovnako musí byť nastavená v nginx (client_max_body_size) / apache alebo na proxy." max_attachment_size_kb: "Mmaximálna veľkosť vloženej prílohy v kB. Rovnako musí byť nastavená v nginx (client_max_body_size) / apache alebo na proxy." authorized_extensions: "Zoznam povolených príloh súborov ktoré je umožnené vkladať (použite '*' na vkladanie súborov všetkých typov)" max_similar_results: "Koľko podobných tém sa má zobraziť nad editorom ak vytvára novú tému. Porovnanie je založené na nadpise a tele správy." diff --git a/config/locales/server.sq.yml b/config/locales/server.sq.yml index 424e657d82..5487ad6248 100644 --- a/config/locales/server.sq.yml +++ b/config/locales/server.sq.yml @@ -755,7 +755,6 @@ sq: min_title_similar_length: "The minimum length of a title before it will be checked for similar topics." category_colors: "A list of hexadecimal color values allowed for categories." category_style: "Visual style for category badges." - max_image_size_kb: "The maximum image upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well." max_attachment_size_kb: "The maximum attachment files upload size in kB. This must be configured in nginx (client_max_body_size) / apache or proxy as well." authorized_extensions: "A list of file extensions allowed for upload (use '*' to enable all file types)" max_similar_results: "How many similar topics to show above the editor when composing a new topic. Comparison is based on title and body." diff --git a/config/locales/server.sr.yml b/config/locales/server.sr.yml index 839bc4d1b3..ebfd0ef55d 100644 --- a/config/locales/server.sr.yml +++ b/config/locales/server.sr.yml @@ -218,7 +218,6 @@ sr: max_replies_in_first_day: "Maksimalan broj odgovora koje korisnik može da kreira u prvih 24 sata nakon kreiranja svoje prve poruke." pending_users_reminder_delay: "Obavesti moderatore ako novi korisnik čeka na odobrenje duže nego ovoliko časova. Podesiti na -1 da bi se onemogućile notifikacije." maximum_session_age: "Korisnik će ostati ulogovan n časova od prethodnog logovanja" - max_image_megapixels: "Maksimalan dozvoljeni broj megapiksela za slike." topic_views_heat_low: "Nakon ovoliko pregleda, polje pregleda je blago označeno." topic_views_heat_medium: "Nakon ovoliko pregleda, polje pregleda je umereno označeno." topic_views_heat_high: "Nakon ovoliko pregleda, polje pregleda je jako označeno." diff --git a/config/locales/server.sv.yml b/config/locales/server.sv.yml index 2c3d28517b..68dc3866d4 100644 --- a/config/locales/server.sv.yml +++ b/config/locales/server.sv.yml @@ -1053,6 +1053,7 @@ sv: labels: level: Nivå description: "Antalet användare fördelat på förtroendenivå." + description_link: "https://blog.discourse.org/2018/06/understanding-discourse-trust-levels/" users_by_type: title: "Användare per typ" xaxis: "Typ" diff --git a/config/locales/server.tr_TR.yml b/config/locales/server.tr_TR.yml index fd09188ce4..8df329d753 100644 --- a/config/locales/server.tr_TR.yml +++ b/config/locales/server.tr_TR.yml @@ -1633,13 +1633,11 @@ tr_TR: desktop_category_page_style: "/categories sayfasının görsel biçimi." category_colors: "Kategoriler için izin verilen onaltılı renk değerlerinin listesi" category_style: "Kategori rozetleri için görsel biçim." - max_image_size_kb: "Yüklenebilecek resmin KB cinsinden en fazla büyüklüğü. Bu nginx (client_max_body_size) / apache veya proxyde de ayarlanmalı." max_attachment_size_kb: "Yüklenebilecek dosyaların KB cinsinden en fazla büyüklüğü. Bu nginx (client_max_body_size) / apache veya proxyde de ayarlanmalı." authorized_extensions: "Yüklenebilecek dosya uzantılarının listesi (tüm dosya türlerini etkinleştirmek için '*' kullanın)" authorized_extensions_for_staff: "`Yetkili_uzanımlar` site ayarında tanımlanan listeye ek olarak yetkili kullanıcılar için yüklenmeye izin verilen dosya uzantılarının listesi. (tüm dosya türlerini etkinleştirmek için '*' kullanın)" theme_authorized_extensions: "Tema yüklemeleri için izin verilen dosya uzantılarının listesi (tüm dosya türlerini etkinleştirmek için '*' kullanın)" max_similar_results: "Yeni bir konu oluştururken, düzenleyicinin üzerinde gösterilecek benzer konuların sayısı. Karşılaştırmalar başlık ve içerik üzerinden yapılır." - max_image_megapixels: "Bir görüntü için izin verilen maksimum megapiksel sayısı." title_prettify: "Tümü büyük harf, ilk karakteri küçük harf, çoklu ! ve ?, sonda ekstra . kullanımı gibi, sık yapılan yazım hatalarını önle." title_remove_extraneous_space: "Noktalama işaretlerinin önündeki ön boşlukları kaldırın." automatic_topic_heat_values: 'Site etkinliğine dayalı olarak "En çok görüntülenen konular" ve "En popüler konu gönderileri" ayarlarını otomatik olarak güncelleyin.' diff --git a/config/locales/server.uk.yml b/config/locales/server.uk.yml index 693bbd4517..5c240cf6e0 100644 --- a/config/locales/server.uk.yml +++ b/config/locales/server.uk.yml @@ -1633,13 +1633,11 @@ uk: desktop_category_page_style: "Візуальний стиль для сторінки категорії." category_colors: "Список шістнадцятирічних кодів кольорів, дозволених для категорій." category_style: "Стилі для виділення розділів." - max_image_size_kb: "Максимальний розмір завантажуваних картинок в кілобайтах. Переконайтеся, що ви також налаштували обмеження в nginx (client_max_body_size) / apache або проксі." max_attachment_size_kb: "Максимальний розмір завантажуваних файлів в кілобайтах. Переконайтеся, що ви також налаштували обмеження в nginx (client_max_body_size) / apache або проксі." authorized_extensions: "Список розширень файлів, дозволених до завантаження. Використовуйте '*', щоб дозволити будь-які типи файлів." authorized_extensions_for_staff: "Список розширень файлів, дозволених для завантаження для користувачів персоналу на додатково до списку, визначеного в налаштуваннях сайту як `authorized_extensions`. (використовувати '*', щоб увімкнути всі типи файлів)" theme_authorized_extensions: "Список розширень файлів, дозволених для завантаження в темі (використовуйте '*', щоб увімкнути всі типи файлів)" max_similar_results: "Кількість схожих тим, що показуються користувачеві під час створення нової теми. Порівняння виконується на підставі назви і тексту теми." - max_image_megapixels: "Максимально допустима кількість мегапікселів для зображення." title_prettify: "Запобігати типовим опискам та помилкам, таким як: всі літери - великі, перша літера - мала, багаторазові ! та ?, надлишкові . в кінці, тощо." title_remove_extraneous_space: "Видаліть початкові пробіли перед кінцевою пунктуацією." automatic_topic_heat_values: 'Автоматично оновлювати параметри "topic views heat" та "topic post like heat" на основі активності сайту.' diff --git a/config/locales/server.ur.yml b/config/locales/server.ur.yml index 368e734edb..38a8762336 100644 --- a/config/locales/server.ur.yml +++ b/config/locales/server.ur.yml @@ -1564,13 +1564,11 @@ ur: desktop_category_page_style: " /categories صفحے کیلئے بصری سٹائل۔" category_colors: "زُمرہ جات کیلئے ہیکسا ڈَیسیمل رنگوں کے اقدار کی ایک فہرست۔" category_style: "زُمرہ بیَجوں کیلئے بصری سٹائل۔" - max_image_size_kb: "kB میں تصویر اَپ لوڈ کا زیادہ سے زیادہ سائز۔ یہ اِنجَن٘ اَیکس (client_max_body_size) / اَپَیچی یا پراکسی میں بھی ترتیب دیا جانا لازمی ہے۔" max_attachment_size_kb: "kB میں اٹیچمنٹ فائل اَپ لوڈ کا زیادہ سے زیادہ سائز۔ یہ اِنجَن٘ اَیکس (client_max_body_size) / اَپَیچی یا پراکسی میں بھی ترتیب دیا جانا لازمی ہے۔" authorized_extensions: "اپ لوڈ کیلئے اجازت یافتہ فائل اَیکسٹَینشَنز کی فہرست (تمام فائل اقسام کی اجازت دینے کیلئے '*' کا استعمال کریں)" authorized_extensions_for_staff: "سٹاف صارفین کیلئے `authorized_extensions` سائٹ ترتیب میں بیان کردہ فہرست کے علاوہ اَپ لوڈ کیلئے اجازت یافتہ فائل اَیکسٹَینشَنز کی فہرست۔ (تمام فائل اقسام کی اجازت دینے کیلئے '*' کا استعمال کریں)" theme_authorized_extensions: "تھِیم اپ لوڈز کیلئے اجازت یافتہ فائل اَیکسٹَینشَنز کی فہرست (تمام فائل اقسام کی اجازت دینے کیلئے '*' کا استعمال کریں)" max_similar_results: "ایک نیا ٹاپک کمپوز کرتے وقت کتنے اُسی جیسے دوسرے ٹاپک اَیڈیٹر کے اوپر دکھائے جائیں۔ موازنہ عنوان اور متن پر مبنی ہے۔" - max_image_megapixels: "ایک تصویر کیلئے مَیگا پِکسل کی زیادہ سے زیادہ عدد۔" title_prettify: "عام عنوان ٹائپینگ کی غلطیوں کو روکیں، بشمول تمام کَیپس، سب سے پہلے حرف کا لوئر کََیس ہونا، کئی! اور؟، آخر میں اضافی ۔، وغیرہ" title_remove_extraneous_space: "آخری وقفی علامت کے آگے سے خالی جگہیں ہٹا دیں۔" automatic_topic_heat_values: 'سائٹ کی سرگرمیوں پر مبنی "ٹاپک وِیوز گرمی" اور "ٹاپک پوسٹ لائیک گرمی" کی ترتیبات خود بخود اپ ڈیٹ کریں۔' diff --git a/config/locales/server.vi.yml b/config/locales/server.vi.yml index d56aaaf092..454c36a78b 100644 --- a/config/locales/server.vi.yml +++ b/config/locales/server.vi.yml @@ -852,7 +852,6 @@ vi: min_title_similar_length: "Chiều dài tối thiểu của tiêu đề trước khi kiểm tra trùng chủ đề." category_colors: "Danh sách mã màu hexa cho phép cho danh mục." category_style: "Style trực quan cho phù hiệu danh mục." - max_image_size_kb: "Kích cỡ ảnh upload tối đa theo Kb. Thiết lập này phải được cấu hình cả trong nginx (client_max_body_size) / apache hoặc trong proxy." max_attachment_size_kb: "Kích thước file tải lên tối đa tính theo kB. đã cấu hình trong nginx (client_max_body_size) / apache hoặc proxy." authorized_extensions: "Danh sách định dạng file cho phép tải lên (sử dụng '*' để cho phép tất cả loại tập tin)" max_similar_results: "Số lượng chủ đề tương tự hiển thị phía trên bộ soạn thảo khi soạn chủ đề mới, so sánh dựa trên tiêu đề và nội dung." diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index a0f9bcc900..af53b87eb5 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -274,6 +274,7 @@ zh_CN: pm_reached_recipients_limit: "抱歉,私信中的收信人不能超过%{recipients_limit}。" removed_direct_reply_full_quotes: "自动删除整个上篇帖子的引用。" secure_upload_not_allowed_in_public_topic: "抱歉,无法在公开的主题中使用以下安全上传:%{upload_filenames}。" + create_pm_on_existing_topic: "抱歉,你无法在现有主题上创建PM。" just_posted_that: "太类似于你最近发表的内容" invalid_characters: "包含无效字符" is_invalid: "似乎不清楚,这是一个完整的句子? " @@ -1600,13 +1601,13 @@ zh_CN: desktop_category_page_style: "/categories 页面的视觉样式。" category_colors: "设置分类颜色的十六进制色彩值列表。" category_style: "分类图标的视觉样式。" - max_image_size_kb: "允许用户上传的最大文件大小(以kB为单位)。确保也在nginx(client_max_body_size),apache 或代理中进行限制文件大小的配置。" + max_image_size_kb: "以kB为单位的上传图像最大尺寸。必须同样在nginx(client_max_body_size)/ apache或代理中配置。大于或小于client_max_body_size的图片将被在上传时调整至适当的大小。" max_attachment_size_kb: "允许用户上传的最大文件大小(单位:KB)——同时在 nginx(client_max_body_size),apache 或代理中配置他们。" authorized_extensions: "允许上传文件的扩展名列表('*' 表示允许所有文件类型)" authorized_extensions_for_staff: "除了在“authorized_extensions”站点设置中定义的列表之外,还运行管理人员上传的文件扩展名列表。(使用'*'启用所有文件类型)" theme_authorized_extensions: "主题上传可用的文件扩展名列表(“*” 可允许所有文件)" max_similar_results: "当用户撰写新主题时,显示多少类似主题给用户。比较是根据标题和内容进行的。" - max_image_megapixels: "图片允许的最大像素。" + max_image_megapixels: "以百万像素为单位单个图像允许的最大值。高于最大值百万像素的图像将被拒绝。" title_prettify: "防止常见标题里的错别字和错误,包括全部大写,第一个字符小写,多个'!'和'?',结尾多余的'.'等等。" title_remove_extraneous_space: "删除结尾标点前的空格。" automatic_topic_heat_values: '基于站点活动自动更新“主题观点热度”和“主题帖子赞的主题热度”设置。' @@ -1646,6 +1647,8 @@ zh_CN: reviewable_claiming: "是否需要审核可审核的内容才能对其进行操作?" reviewable_default_topics: "默认以主题为分组显示可审核内容" reviewable_default_visibility: "满足此优先级前不要显示可审核条目" + high_trust_flaggers_auto_hide_posts: "新用户的发帖被信任等级3+的用户标记为垃圾后将被自动隐藏。" + cooldown_hours_until_reflag: "用户需要等待多长时间才能重新标记一个帖子。" reply_by_email_enabled: "启用通过邮件回复。" reply_by_email_address: "通过邮件回复的回复地址模板,例如:%%{reply_key}@reply.example.com 或 replies+%%{reply_key}@example.com" alternative_reply_by_email_addresses: "通过邮件回复的回复地址模板,例如:%%{reply_key}@reply.example.com|replies+%%{reply_key}@example.com" @@ -1741,6 +1744,7 @@ zh_CN: ignored_users_message_gap_days: "当一个用户被很多用户忽视时再次通知版主要等待多久。" clean_up_inactive_users_after_days: "非活跃用户(信任等级0且没有任何帖子)被删除前等待的天数。设为0则关闭清理。" user_selected_primary_groups: "允许用户设置其主要群组" + max_notifications_per_user: "每个用户的最大通知数量,如超出,旧的通知将被删除。每周执行一次。设为0以关闭。" user_website_domains_whitelist: "用户网站要属于这些域名中。用 | 分割。" allow_profile_backgrounds: "允许用户上传个人资料背景图片。" sequential_replies_threshold: "在被提醒回复了太多连续的回复前,用户在主题中可以连续回复的帖子的数量。" diff --git a/config/locales/server.zh_TW.yml b/config/locales/server.zh_TW.yml index 78dc673ab1..2221178662 100644 --- a/config/locales/server.zh_TW.yml +++ b/config/locales/server.zh_TW.yml @@ -1480,13 +1480,11 @@ zh_TW: desktop_category_page_style: "/categories 頁面的視覺樣式。" category_colors: "設定分類顏色的十六進制色彩值列表。" category_style: "分類圖標的視覺樣式。" - max_image_size_kb: "允許使用者上傳的最大圖片大小(以kB為單位)。確保也在nginx(client_max_body_size),apache 或代理中進行限制文件大小的設定。" max_attachment_size_kb: "允許使用者上傳的最大文件大小(以kB為單位)。確保也在nginx(client_max_body_size),apache 或代理中進行限制文件大小的設定。" authorized_extensions: "允許上傳文件的副檔名列表('*' 表示允許所有文件類型)" authorized_extensions_for_staff: "除了在“authorized_extensions” 可以設定網站可允許上傳副檔名的清單之外,也允許管理員(有權限的員工)為使用者上載檔案副檔名清單。(使用 星字號 * 以啟用所有檔案類型)" theme_authorized_extensions: "允許佈景主題上傳的檔案副檔名列表(使用星字號 * 啟用所有文件類型)" max_similar_results: "當使用者撰寫新主題時,顯示多少類似主題給使用者。比較根據標題和內容進行。" - max_image_megapixels: "圖像所允許的最大百萬畫素數質。" title_prettify: "防止常見標題裡的錯別字和錯誤,包括全部大寫,首字小寫,多個!和?,結尾多餘的. 等等。" topic_views_heat_low: "多少次瀏覽後,該視圖將稍稍高亮。" topic_views_heat_medium: "多少次瀏覽後,該視圖將明顯高亮。" diff --git a/plugins/discourse-local-dates/config/locales/client.bs_BA.yml b/plugins/discourse-local-dates/config/locales/client.bs_BA.yml index de9010fbb9..3fcb6e6c27 100644 --- a/plugins/discourse-local-dates/config/locales/client.bs_BA.yml +++ b/plugins/discourse-local-dates/config/locales/client.bs_BA.yml @@ -8,6 +8,13 @@ bs_BA: js: discourse_local_dates: + relative_dates: + today: Danas%{time} + tomorrow: Sutra %{time} + yesterday: Jučer %{time} + countdown: + passed: datum je prošao + title: Unesi datum / vrijeme create: form: insert: Unesi @@ -17,7 +24,20 @@ bs_BA: timezones_title: Vremenske zone za prikazati timezones_description: Vremenske zone će biti korištene kako bi prikazale datume u pregledu i u nazad. recurring_title: Vraćanje + recurring_description: "Definiši ponavljanje eventa. Možete također menuelno izmijeniti opcije ponavljanja generisanih od strane foruma i koristiti jedan od sljedećih ključeva: godine, kvartali, mjeseci, sedmice, dani, sati, minute, sekunde, milisekunde." + recurring_none: Bez ponavljanja invalid_date: Neispravan datum, osigurajte da su datum i vrijeme tačni date_title: Datum time_title: Vrijeme format_title: Format datuma + timezone: Vremenska zona + until: Sve do... + recurring: + every_day: "Svaki dan" + every_week: "Svake sedmice" + every_two_weeks: "Svake dvije sedmice" + every_month: "Svaki mjesec" + every_two_months: "Svaka dva mjeseca" + every_three_months: "Svaka tri mjeseca" + every_six_months: "Svakih šest mjeseci" + every_year: "Svake godine" diff --git a/plugins/discourse-local-dates/config/locales/client.fa_IR.yml b/plugins/discourse-local-dates/config/locales/client.fa_IR.yml index b2214bb0f1..b67c306f03 100644 --- a/plugins/discourse-local-dates/config/locales/client.fa_IR.yml +++ b/plugins/discourse-local-dates/config/locales/client.fa_IR.yml @@ -22,3 +22,4 @@ fa_IR: date_title: تاریخ time_title: زمان format_title: فرمت تاریخ + timezone: منطقه ی زمانی diff --git a/plugins/discourse-narrative-bot/config/locales/server.bs_BA.yml b/plugins/discourse-narrative-bot/config/locales/server.bs_BA.yml index d912946b5e..57e1762b4f 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.bs_BA.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.bs_BA.yml @@ -26,6 +26,14 @@ bs_BA: Ovaj bedž je dodjeljen prilikom uspješnog završetka interaktivnog tutorijala za nove korisnike. Postali ste majstor naprednih alata u diskusiji - sada ste potpuno licencirani! discourse_narrative_bot: bio: "Pozdrav, ja nisam stvarna osoba. Ja sam automatski robot koji će vas naučiti kako da koristite ovaj web sajt. Kako bi komunicirali sa mnom, pošaljite mi poruku ili me spomenite pisajući **`@%{discobot_username}`** bilo gdje." + tl2_promotion_message: + subject_template: "Čestitamo na povišenju vašeg nivoa povjerenja!" + text_body_template: | + Sada kada vam je povišen nivo povjerenja, došlo je vrijeme da naučite neke napredne mogućnosti! + + Odgovori na ovu poruku sa `@%{discobot_username} %{reset_trigger}` kako bi saznali nešto više o tome šta je moguće sve raditi. + + Pozivamo vas da se i dalje ovdje uključite - uživamo što vas imamo ovdje na forumu. timeout: message: |- Hej @%{username}, samo vas provjeravam jer nisam vas čuo neko vrijeme. @@ -113,6 +121,20 @@ bs_BA: random_mention: reply: |- Pozdrav! Kako bi saznali šta sve mogu raditi, recite `@%{discobot_username} %{help_trigger}`. + tracks: |- + Trenutno znam kako uraditi sljedeće stvari: + + `@%{discobot_username} %{reset_trigger} {ime-tutorijala}` + > Starta interaktivni tutorijal. `{ime-tutorijala}` može biti jedan od `%{tracks}`. + bot_actions: |- + `@%{discobot_username} %{dice_trigger} 2d6` + > :game_die: 3, 6 + + `@%{discobot_username} %{quote_trigger}` + %{quote_sample} + + `@%{discobot_username} %{magic_8_ball_trigger}` + > :crystal_ball: Možeš se na to osloniti do_not_understand: first_response: |- Hej, hvala za odgovor! @@ -190,6 +212,12 @@ bs_BA: search: instructions: |- _psst_… Sakrio sam iznenađenje u ovoj temi. Ako ste spremni za izazov, ** odaberite ikonu za pretraživanje ** gore desno ↗ da ga potražite. Pokušajte tražiti pojam "capy​bara" u ovoj temi + hidden_message: |- + Kako ste uspjeli propustiti ovu kapibaru? :wink: + + + + Dali ste primjetili da ste sada na početku? Nahranite ovog jadnog gladnog kapibaru tako što će te **odgovoriti sa `%{search_answer}` emoji-em** i bit će te automatski vraćeni na kraj. reply: |- Yay ste ga pronašli: tada: - Za detaljnije pretrage, pređite na [full search page] (%{search_url}). - Da biste skočili bilo gdje u dugoj diskusiji, pokušajte kontrolirati vremensku liniju teme desno (i na dnu, na mobitelu). - Ako imate fizičku tipkovnicu: pritisnite ? da biste videli naše korisne prečice na tastaturi. not_found: |- diff --git a/plugins/discourse-narrative-bot/config/locales/server.nl.yml b/plugins/discourse-narrative-bot/config/locales/server.nl.yml index 55c0363946..da479e2934 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.nl.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.nl.yml @@ -95,6 +95,11 @@ nl: random_mention: reply: |- Hallo! Zeg `@%{discobot_username} %{help_trigger}` om te ontdekken wat ik kan. + tracks: |- + Momenteel kan ik de volgende dingen doen: + + `@%{discobot_username} %{reset_trigger} {name-of-tutorial}` + > Start een interactieve handleiding. `{name-of-tutorial}` kan één zijn van: `%{tracks}`. do_not_understand: first_response: |- Hallo, bedankt voor het antwoord! @@ -103,8 +108,26 @@ nl: track_response: U kunt het opnieuw proberen, of als u deze stap wilt overslaan, `%{skip_trigger}` zeggen. Zeg anders `%{reset_trigger}` om opnieuw te beginnen. new_user_narrative: reset_trigger: "handleiding" + title: "Certificaat voor het invullen van een handleiding voor nieuwe gebruikers" + cert_title: "Als erkenning voor de succesvolle afronding van de gebruikershandleiding voor nieuwe gebruikers" hello: title: "Gegroet!" + formatting: + reply: |- + Uitstekend werk! HTML en BBCode werken ook voor de opmaak – om meer te leren, [probeer deze handleiding](http://commonmark.org/help) :nerd: + not_found: |- + Oh, ik vond geen opmaak in je antwoord. :pencil2: + + Kan je opnieuw proberen? Gebruik de B vet of I cursief knoppen in de editor als je vast komt te zitten. + search: + reply: |- + Joepie! Je hebt het gevonden :tada: + + - Voor meer gedetailleerde zoekopdrachten gaat u naar de [geavanceerde zoekpagina](%{search_url}). + + - Om naar eender waar in een lange discussie te springen, probeer de tijdslijnbediening aan de rechterzijde (en onderaan, op mobiele aparaten). + + - Indien je een fysiek toetsenbord hebt :keyboard:, druk ? om onze handige snelkoppelingen te bekijken. advanced_user_narrative: reset_trigger: "geavanceerde handleiding" title: ":arrow_up: Geavanceerde gebruikersfuncties" diff --git a/plugins/poll/config/locales/client.bs_BA.yml b/plugins/poll/config/locales/client.bs_BA.yml index c343660c22..379da2075a 100644 --- a/plugins/poll/config/locales/client.bs_BA.yml +++ b/plugins/poll/config/locales/client.bs_BA.yml @@ -17,14 +17,25 @@ bs_BA: few: "ukupno glasova" other: "ukupno glasova" average_rating: "Prosječna ocjena: %{average}." + public: + title: "Glasanje je javno." + results: + groups: + title: "Morate biti pripadnik %{groups} kako bi ste mogli glasati u ovoj anketi." + vote: + title: "Rezultati će biti prikazani pritiskom naglasaj." + closed: + title: "Rezultati će biti prikazani onda kada glasanje bude završeno." + staff: + title: "Rezultati su prikazani samo uredništvu i admin korisnicima." multiple: help: at_least_min_options: one: "Odaberi barem %{count} opciju" - few: "Odaberi barem %{name} opcije" - other: "Odaberi barem %{name} opcija" + few: "Odaberi barem %{count} opcije" + other: "Odaberi barem %{count} opcija" up_to_max_options: - one: "Odaberi do %{count} opcije" + one: "Odaberi do %{count} opciju" few: "Odaberi do %{count} opcije" other: "Odaberi do %{count} opcija" x_options: @@ -40,7 +51,15 @@ bs_BA: label: "Prikaži rezultate" hide-results: title: "Nazad na glasove" + label: "Prikaži glasanje" + group-results: + title: "Grupiraj glasove po polju korisnika" + label: "Prikaži raspodjelu" + ungroup-results: + title: "Kombiniraj sve glasove" + label: "Sakrij raspodjelu" export-results: + title: "Izvezi rezultate ankete (Export)" label: "Izvoz" open: title: "Otvori anketu" @@ -50,13 +69,18 @@ bs_BA: title: "Zatvori anketu" label: "Zatvori" confirm: "Da li ste sigurni da želite da zatvorite ovu anketu?" + automatic_close: + closes_in: "Završava za %{timeLeft}." + age: "Završeno %{age}" error_while_toggling_status: "Izvinjavamo se, pojavio se problem u prebacivanju statutusa ove ankete" error_while_casting_votes: "Izvinjavamo se, pojavila se greška prikazivanja vaših glasova" error_while_fetching_voters: "Izvinjavamo se, pojavila se greška pri prikazivanju glasača" + error_while_exporting_results: "Izvinjavamo se, došlo je do greške izvoza rezultata vaše ankete." ui_builder: title: Izgradi anketu insert: Umetni anketu help: + options_count: Unesite barem jednu opciju invalid_values: Minimalna vrijednost mora biti manja od maksimalne. min_step_value: Minimalna vrijednost razmaka je 1 poll_type: @@ -66,6 +90,14 @@ bs_BA: number: Rejting broja poll_result: label: Rezultati + always: Uvjek vidljivo + vote: Prilikom glasanja + closed: Kada se završi + staff: Samo za urednike i admine + poll_groups: + label: Dozvoljene grupe + poll_chart_type: + label: Tip chart grafikona poll_config: max: Maksimalno min: Minimalno diff --git a/plugins/poll/config/locales/server.bs_BA.yml b/plugins/poll/config/locales/server.bs_BA.yml index a347f6a1dc..78bf651b41 100644 --- a/plugins/poll/config/locales/server.bs_BA.yml +++ b/plugins/poll/config/locales/server.bs_BA.yml @@ -11,11 +11,15 @@ bs_BA: poll_maximum_options: "Maksimalan broj dozvoljenih opcija u anketi." poll_edit_window_mins: "Broj minuta nakon kreiranja posta tokom kojih se mogu uređivati ankete." poll_minimum_trust_level_to_create: "Definišite minimalni nivo povjerenja potreban za kreiranje anketa." + poll_groupable_user_fields: "Set polja korisničkih imena koji može biti iskorišten za grupisanje i filtriranje rezultata ankete." + poll_export_data_explorer_query_id: "ID od Data Explorer Query koji se koristi za izvoz (export) rezultata ankete (0 za isključi)." poll: poll: "anketa" invalid_argument: "Nevažeća vrijednost '%{value}' za argument '%{argument}'." multiple_polls_without_name: "Postoji više anketa bez imena. Koristite atribut „ name “ da biste jedinstveno identifikovali vaše ankete." multiple_polls_with_same_name: "Postoji više anketa sa istim imenom: %{name} . Koristite atribut „ name “ da biste jedinstveno identifikovali vaše ankete." + default_poll_must_have_at_least_1_option: "Anketa mora imati barem 1 opciju." + named_poll_must_have_at_least_1_option: "Anketa imenovana %{name} mora imati barem 1 opciju." default_poll_must_have_less_options: one: "Anketa mora imati manje od %{count} opcije." few: "Anketa mora imati manje od %{count} opcija." @@ -26,6 +30,8 @@ bs_BA: other: "Anketa nazvana %{name} mora imati manje od %{count} opcija." default_poll_must_have_different_options: "Anketa mora imati različite opcije." named_poll_must_have_different_options: "Anketa nazvana %{name} mora imati različite opcije." + default_poll_must_not_have_any_empty_options: "Anketa ne smije imati praznu opciju." + named_poll_must_not_have_any_empty_options: "Anketa imenovana sa %{name} ne smije imati prazne opcije." default_poll_with_multiple_choices_has_invalid_parameters: "Anketa sa više izbora ima nevažeće parametre." named_poll_with_multiple_choices_has_invalid_parameters: "Anketa nazvana %{name} sa višestrukim izborom ima nevažeće parametre." requires_at_least_1_valid_option: "Morate odabrati najmanje 1 važeću opciju." @@ -42,3 +48,5 @@ bs_BA: insufficient_rights_to_create: "Nije vam dozvoljeno da kreirate ankete." email: link_to_poll: "Kliknite za pregled ankete." + user_field: + no_data: "Bez podataka" From 5b3630dba3764ca5aabed6f8cdd1b0bd17ded175 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 5 Mar 2020 17:50:29 +0000 Subject: [PATCH 0087/1830] FIX: Do not raise an error when in:all search is performed by anon (#9113) Also improve in:all specs to catch to catch similar failures --- lib/search.rb | 2 +- spec/components/search_spec.rb | 37 ++++++++++++++++------------------ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/lib/search.rb b/lib/search.rb index 1869c0ce45..e7e97d8ede 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -176,7 +176,7 @@ class Search @search_context = @guardian.user end - if @search_all_topics + if @search_all_topics && @guardian.user @opts[:type_filter] = "all_topics" end diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index 7e5590c989..c4578148d7 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -315,56 +315,53 @@ describe Search do TopicAllowedUser.create!(user_id: u2.id, topic_id: private_topic.id) # private only - results = Search.execute('cheese', - type_filter: 'all_topics', + results = Search.execute('in:all cheese', guardian: Guardian.new(u1)) expect(results.posts.length).to eq(1) # public only - results = Search.execute('eggs', - type_filter: 'all_topics', + results = Search.execute('in:all eggs', guardian: Guardian.new(u1)) expect(results.posts.length).to eq(1) # both - results = Search.execute('spam', - type_filter: 'all_topics', + results = Search.execute('in:all spam', guardian: Guardian.new(u1)) expect(results.posts.length).to eq(2) + # for anon + results = Search.execute('in:all spam', + guardian: Guardian.new) + expect(results.posts.length).to eq(1) + # nonparticipatory user - results = Search.execute('cheese', - type_filter: 'all_topics', + results = Search.execute('in:all cheese', guardian: Guardian.new(u3)) expect(results.posts.length).to eq(0) - results = Search.execute('eggs', - type_filter: 'all_topics', + results = Search.execute('in:all eggs', guardian: Guardian.new(u3)) expect(results.posts.length).to eq(1) - results = Search.execute('spam', - type_filter: 'all_topics', + results = Search.execute('in:all spam', guardian: Guardian.new(u3)) expect(results.posts.length).to eq(1) # Admin doesn't see private topic - results = Search.execute('spam', - type_filter: 'all_topics', + results = Search.execute('in:all spam', guardian: Guardian.new(u4)) expect(results.posts.length).to eq(1) # same keyword for different users - results = Search.execute('ham', - type_filter: 'all_topics', + results = Search.execute('in:all ham', guardian: Guardian.new(u1)) expect(results.posts.length).to eq(2) - results = Search.execute('ham', - type_filter: 'all_topics', + + results = Search.execute('in:all ham', guardian: Guardian.new(u2)) expect(results.posts.length).to eq(2) - results = Search.execute('ham', - type_filter: 'all_topics', + + results = Search.execute('in:all ham', guardian: Guardian.new(u3)) expect(results.posts.length).to eq(1) end From a46741cbb96cd7d6463fb345352707af36d8d859 Mon Sep 17 00:00:00 2001 From: Justin DiRose Date: Thu, 5 Mar 2020 12:25:10 -0600 Subject: [PATCH 0088/1830] DEV: Clean up selectors on backup modal (#9114) --- .../javascripts/admin/templates/modal/admin-start-backup.hbs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs b/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs index dd201e2aed..011de55de9 100644 --- a/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs +++ b/app/assets/javascripts/admin/templates/modal/admin-start-backup.hbs @@ -1,12 +1,14 @@ {{#d-modal-body title="admin.backups.operations.backup.confirm"}} {{d-button - class="btn-primary" + class="btn-primary backup-with-uploads" action=(action "startBackupWithUploads") label="yes_value"}} {{d-button + class="backup-no-uploads" action=(action "startBackupWithoutUploads") label="admin.backups.operations.backup.without_uploads"}} {{d-button + class="btn-default" action=(action "cancel") label="no_value"}} {{/d-modal-body}} From 10ddb8a9c4bea55ea4f921b893c42635e79c6b70 Mon Sep 17 00:00:00 2001 From: Kane York Date: Thu, 5 Mar 2020 10:51:51 -0800 Subject: [PATCH 0089/1830] FIX: Use destroy_all instead of delete_all for shared drafts Rails has an odd behavior for calling .delete_all on a has_many relation - the default behavior is to nullify the foreign key fields instead of actually 'DELETE'ing the records. Additionally, publishing a shared draft topic creates a PostRevision that the NotifyPostRevision job picks up which is then promptly deleted. Use destroy_all when cleaning up the revisions and have the NotifyPostRevision job tolerate deleted PostRevision records. This takes a small performance hit (several SQL DELETEs instead of just one) but shouldn't be too much of an issue (high cardinalities range from 30-100). --- app/jobs/regular/notify_post_revision.rb | 2 +- lib/topic_publisher.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/regular/notify_post_revision.rb b/app/jobs/regular/notify_post_revision.rb index 8d2160699c..f4b0262e06 100644 --- a/app/jobs/regular/notify_post_revision.rb +++ b/app/jobs/regular/notify_post_revision.rb @@ -6,7 +6,7 @@ module Jobs raise Discourse::InvalidParameters.new(:user_ids) unless args[:user_ids] post_revision = PostRevision.find_by(id: args[:post_revision_id]) - raise Discourse::InvalidParameters.new(:post_revision_id) unless post_revision + return if post_revision.nil? ActiveRecord::Base.transaction do User.where(id: args[:user_ids]).find_each do |user| diff --git a/lib/topic_publisher.rb b/lib/topic_publisher.rb index b78b58bd11..63afb8dede 100644 --- a/lib/topic_publisher.rb +++ b/lib/topic_publisher.rb @@ -36,7 +36,7 @@ class TopicPublisher op = @topic.first_post if op.present? - op.revisions.delete_all + op.revisions.destroy_all op.update_columns( version: 1, From 670b855f947052d990b27599e14cdd176257ed6b Mon Sep 17 00:00:00 2001 From: Kane York Date: Thu, 5 Mar 2020 11:19:22 -0800 Subject: [PATCH 0090/1830] FEATURE: Treat /go/ as a server-side route Ninja superuser implementation of routable permalinks with no UI or permission changes yet. --- app/assets/javascripts/discourse/lib/url.js.es6 | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6 index 3dc13d0d79..c09baee201 100644 --- a/app/assets/javascripts/discourse/lib/url.js.es6 +++ b/app/assets/javascripts/discourse/lib/url.js.es6 @@ -25,6 +25,7 @@ const SERVER_SIDE_ONLY = [ /^\/posts\/\d+\/raw/, /^\/raw\/\d+/, /^\/wizard/, + /^\/go\//, // EXPERIMENTAL: https://meta.discourse.org/t/-/142605 /\.rss$/, /\.json$/, /^\/admin\/upgrade$/, From 9ab2a15691de4c280e234be8d50b0526b657db83 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 5 Mar 2020 15:37:49 -0500 Subject: [PATCH 0091/1830] Warn if their CDN URL doesn't have a protocol This can be confusing: https://meta.discourse.org/t/discourse-cdn-url-breaks-rebuild-restore/136844 --- config/application.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/application.rb b/config/application.rb index 52820120be..e2b271c947 100644 --- a/config/application.rb +++ b/config/application.rb @@ -35,6 +35,9 @@ unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1" require_relative '../lib/custom_setting_providers' end GlobalSetting.load_defaults +if GlobalSetting.try(:cdn_url).present? && GlobalSetting.cdn_url !~ /^https?:\/\// + STDERR.puts "WARNING: Your CDN URL does not begin with a protocol like `https://` - this is probably not going to work" +end if ENV['SKIP_DB_AND_REDIS'] == '1' GlobalSetting.skip_db = true From d1cceff0e7c4c36e4ec3c38bd8fd7899b69566cc Mon Sep 17 00:00:00 2001 From: Kane York Date: Thu, 5 Mar 2020 12:46:03 -0800 Subject: [PATCH 0092/1830] DEV: fix formatting --- app/assets/javascripts/discourse/lib/url.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/url.js.es6 b/app/assets/javascripts/discourse/lib/url.js.es6 index c09baee201..93cad9b4c4 100644 --- a/app/assets/javascripts/discourse/lib/url.js.es6 +++ b/app/assets/javascripts/discourse/lib/url.js.es6 @@ -25,7 +25,7 @@ const SERVER_SIDE_ONLY = [ /^\/posts\/\d+\/raw/, /^\/raw\/\d+/, /^\/wizard/, - /^\/go\//, // EXPERIMENTAL: https://meta.discourse.org/t/-/142605 + /^\/go\//, // EXPERIMENTAL: https://meta.discourse.org/t/-/142605 /\.rss$/, /\.json$/, /^\/admin\/upgrade$/, From 4bb8db024c247f20af9245723ebea4c474eeb16a Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 5 Mar 2020 16:04:31 -0500 Subject: [PATCH 0093/1830] FIX: Don't allow people to clear the upload bucket while it's enabled --- lib/site_settings/validations.rb | 2 ++ spec/lib/site_settings/validations_spec.rb | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/site_settings/validations.rb b/lib/site_settings/validations.rb index 56987b0dfe..0bf13f7606 100644 --- a/lib/site_settings/validations.rb +++ b/lib/site_settings/validations.rb @@ -143,6 +143,8 @@ module SiteSettings::Validations def validate_s3_upload_bucket(new_val) validate_bucket_setting("s3_upload_bucket", new_val, SiteSetting.s3_backup_bucket) + + validate_error(:s3_upload_bucket_is_required, setting_name: 's3_upload_bucket') if new_val.blank? && SiteSetting.enable_s3_uploads? end def validate_s3_backup_bucket(new_val) diff --git a/spec/lib/site_settings/validations_spec.rb b/spec/lib/site_settings/validations_spec.rb index 7f346d4d5c..69ab73920b 100644 --- a/spec/lib/site_settings/validations_spec.rb +++ b/spec/lib/site_settings/validations_spec.rb @@ -103,6 +103,15 @@ describe SiteSettings::Validations do SiteSetting.s3_backup_bucket = "my-awesome-bucket/foo" expect { validate("my-awesome-bucket/foo/uploads") }.to raise_error(Discourse::InvalidParameters, error_message) end + + it "cannot be made blank unless the setting is false" do + SiteSetting.s3_backup_bucket = "really-real-cool-bucket" + SiteSetting.enable_s3_uploads = true + + expect { validate("") }.to raise_error(Discourse::InvalidParameters) + SiteSetting.enable_s3_uploads = false + validate("") + end end end From 3e21d40bc4b8c92ac3b3a3de0cfdce8b8bbcce5e Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 5 Mar 2020 16:10:28 -0500 Subject: [PATCH 0094/1830] Version bump to v2.5.0.beta2 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 85a9a0503c..2d8503a967 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -9,7 +9,7 @@ module Discourse MAJOR = 2 MINOR = 5 TINY = 0 - PRE = 'beta1' + PRE = 'beta2' STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end From d4fc76b335d012275b06b7ce80d0c1b98f9db33d Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 5 Mar 2020 16:29:49 -0500 Subject: [PATCH 0095/1830] Revert "FIX: Don't allow people to clear the upload bucket while it's enabled" This reverts commit 4bb8db024c247f20af9245723ebea4c474eeb16a. --- lib/site_settings/validations.rb | 2 -- spec/lib/site_settings/validations_spec.rb | 9 --------- 2 files changed, 11 deletions(-) diff --git a/lib/site_settings/validations.rb b/lib/site_settings/validations.rb index 0bf13f7606..56987b0dfe 100644 --- a/lib/site_settings/validations.rb +++ b/lib/site_settings/validations.rb @@ -143,8 +143,6 @@ module SiteSettings::Validations def validate_s3_upload_bucket(new_val) validate_bucket_setting("s3_upload_bucket", new_val, SiteSetting.s3_backup_bucket) - - validate_error(:s3_upload_bucket_is_required, setting_name: 's3_upload_bucket') if new_val.blank? && SiteSetting.enable_s3_uploads? end def validate_s3_backup_bucket(new_val) diff --git a/spec/lib/site_settings/validations_spec.rb b/spec/lib/site_settings/validations_spec.rb index 69ab73920b..7f346d4d5c 100644 --- a/spec/lib/site_settings/validations_spec.rb +++ b/spec/lib/site_settings/validations_spec.rb @@ -103,15 +103,6 @@ describe SiteSettings::Validations do SiteSetting.s3_backup_bucket = "my-awesome-bucket/foo" expect { validate("my-awesome-bucket/foo/uploads") }.to raise_error(Discourse::InvalidParameters, error_message) end - - it "cannot be made blank unless the setting is false" do - SiteSetting.s3_backup_bucket = "really-real-cool-bucket" - SiteSetting.enable_s3_uploads = true - - expect { validate("") }.to raise_error(Discourse::InvalidParameters) - SiteSetting.enable_s3_uploads = false - validate("") - end end end From 54f67661acf04e8c501634823a1c7e183f48c95c Mon Sep 17 00:00:00 2001 From: Rafael dos Santos Silva Date: Thu, 5 Mar 2020 19:21:38 -0300 Subject: [PATCH 0096/1830] FEATURE: Option to connect to Redis using SSL --- app/models/global_setting.rb | 2 ++ config/discourse_defaults.conf | 3 +++ 2 files changed, 5 insertions(+) diff --git a/app/models/global_setting.rb b/app/models/global_setting.rb index eb3592d1e4..57d22d6618 100644 --- a/app/models/global_setting.rb +++ b/app/models/global_setting.rb @@ -172,6 +172,7 @@ class GlobalSetting c[:db] = redis_db if redis_db != 0 c[:db] = 1 if Rails.env == "test" c[:id] = nil if redis_skip_client_commands + c[:ssl] = true if redis_use_ssl c.freeze end @@ -195,6 +196,7 @@ class GlobalSetting c[:db] = message_bus_redis_db if message_bus_redis_db != 0 c[:db] = 1 if Rails.env == "test" c[:id] = nil if message_bus_redis_skip_client_commands + c[:ssl] = true if redis_use_ssl c.freeze end diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf index aee0f88ab2..0a4eb66dd7 100644 --- a/config/discourse_defaults.conf +++ b/config/discourse_defaults.conf @@ -120,6 +120,9 @@ redis_password = # skip configuring client id for cloud providers who support no client commands redis_skip_client_commands = false +# uses SSL for all Redis connections if true +redis_use_ssl = false + # message bus redis server switch message_bus_redis_enabled = false From 243284f998e213034f9f0c6b228f97f7c9834fdd Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Thu, 5 Mar 2020 13:55:35 -1000 Subject: [PATCH 0097/1830] FEATURE: prevent accidental canceling when drafting penalties (#9105) Pop up a confirmation box when there is input. This prevents accidental closing of the dialog boxes due to clicking outside. This adds a development hook on modals in the form of a `beforeClose` function. Modal windows can abort the close if the funtion returns false. Additionally fixing a few issues with loop and state on the modal popups: Escape key with bootbox is keyup. Updating modal to close on keyup as well so escape key is working. Fixes an issue where pressing esc will loop immediately back to the modal by: keydown -> bootbox -> keyup -> acts as "cancel", restores modal Needs a next call to reopenModal otherwise, keyup is handled again by the modal. Fixes an issue where pressing esc will loop immediately back to the confirm: esc keyup will be handled and bubble immediately back to the modal. Additionally, only handle key events when the #discourse-modal is visible. This resolves issues where escape or enter events were being handled by a hidden modal window. --- .../admin/mixins/penalty-controller.js.es6 | 24 +++++++++++++++++- .../discourse/components/d-modal.js.es6 | 17 +++++++------ .../discourse/routes/application.js.es6 | 15 +++++++++-- config/locales/client.en.yml | 1 + .../acceptance/admin-suspend-user-test.js.es6 | 25 +++++++++++++++++++ test/javascripts/acceptance/modal-test.js.es6 | 10 ++++---- 6 files changed, 77 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 index cb07e9d2ca..f923710649 100644 --- a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 +++ b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 @@ -1,6 +1,7 @@ import ModalFunctionality from "discourse/mixins/modal-functionality"; import { popupAjaxError } from "discourse/lib/ajax-error"; import Mixin from "@ember/object/mixin"; +import { next } from "@ember/runloop"; import { Promise } from "rsvp"; export default Mixin.create(ModalFunctionality, { @@ -11,6 +12,7 @@ export default Mixin.create(ModalFunctionality, { user: null, postId: null, successCallback: null, + confirmClose: false, resetModal() { this.setProperties({ @@ -21,10 +23,30 @@ export default Mixin.create(ModalFunctionality, { postEdit: null, postAction: "delete", before: null, - successCallback: null + successCallback: null, + confirmClose: false }); }, + beforeClose() { + // prompt a confirmation if we have unsaved content + if ( + (this.reason && this.reason.length > 1) || + (this.message && this.message.length > 1 && !this.confirmClose) + ) { + this.send("hideModal"); + bootbox.confirm(I18n.t("admin.user.confirm_cancel_penalty"), result => { + if (result) { + this.set("confirmClose", true); + this.send("closeModal"); + } else { + next(() => this.send("reopenModal")); + } + }); + return false; + } + }, + penalize(cb) { let before = this.before; let promise = before ? before() : Promise.resolve(); diff --git a/app/assets/javascripts/discourse/components/d-modal.js.es6 b/app/assets/javascripts/discourse/components/d-modal.js.es6 index 300a3e585c..eeae7edc3f 100644 --- a/app/assets/javascripts/discourse/components/d-modal.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal.js.es6 @@ -31,13 +31,16 @@ export default Component.extend({ @on("didInsertElement") setUp() { - $("html").on("keydown.discourse-modal", e => { - if (e.which === 27 && this.dismissable) { - next(() => $(".modal-header button.modal-close").click()); - } + $("html").on("keyup.discourse-modal", e => { + //only respond to events when the modal is visible + if ($("#discourse-modal:visible").length > 0) { + if (e.which === 27 && this.dismissable) { + next(() => $(".modal-header button.modal-close").click()); + } - if (e.which === 13 && this.triggerClickOnEnter(e)) { - next(() => $(".modal-footer .btn-primary").click()); + if (e.which === 13 && this.triggerClickOnEnter(e)) { + next(() => $(".modal-footer .btn-primary").click()); + } } }); @@ -46,7 +49,7 @@ export default Component.extend({ @on("willDestroyElement") cleanUp() { - $("html").off("keydown.discourse-modal"); + $("html").off("keyup.discourse-modal"); this.appEvents.off("modal:body-shown", this, "_modalBodyShown"); }, diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index e877d8ceff..8dca333360 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -157,12 +157,23 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, { // Close the current modal, and destroy its state. closeModal() { - this.render("hide-modal", { into: "modal", outlet: "modalBody" }); - const route = getOwner(this).lookup("route:application"); let modalController = route.controllerFor("modal"); const controllerName = modalController.get("name"); + if (controllerName) { + const controller = getOwner(this).lookup( + `controller:${controllerName}` + ); + if (controller && controller.beforeClose) { + if (false === controller.beforeClose()) { + return; + } + } + } + + this.render("hide-modal", { into: "modal", outlet: "modalBody" }); + if (controllerName) { const controller = getOwner(this).lookup( `controller:${controllerName}` diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 127c964d04..c7705ab948 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4291,6 +4291,7 @@ en: threshold_reached: "Received too many bounces from that email." trust_level_change_failed: "There was a problem changing the user's trust level." suspend_modal_title: "Suspend User" + confirm_cancel_penalty: "Are you sure you want to discard the penalty?" trust_level_2_users: "Trust Level 2 Users" trust_level_3_requirements: "Trust Level 3 Requirements" trust_level_locked_tip: "trust level is locked, system will not promote or demote user" diff --git a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 b/test/javascripts/acceptance/admin-suspend-user-test.js.es6 index d9983848ca..936f7080bb 100644 --- a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 +++ b/test/javascripts/acceptance/admin-suspend-user-test.js.es6 @@ -34,6 +34,31 @@ QUnit.test("suspend a user - cancel", async assert => { assert.equal(find(".suspend-user-modal:visible").length, 0); }); +QUnit.test("suspend a user - cancel with input", async assert => { + await visit("/admin/users/1234/regular"); + await click(".suspend-user"); + + assert.equal(find(".suspend-user-modal:visible").length, 1); + + await fillIn(".suspend-reason", "for breaking the rules"); + await fillIn(".suspend-message", "this is an email reason why"); + + await click(".d-modal-cancel"); + + assert.equal(find(".bootbox.modal:visible").length, 1); + + await click(".modal-footer .btn-default"); + assert.equal(find(".suspend-user-modal:visible").length, 1); + assert.equal( + find(".suspend-message")[0].value, + "this is an email reason why" + ); + + await click(".d-modal-cancel"); + await click(".modal-footer .btn-primary"); + assert.equal(find(".suspend-user-modal:visible").length, 0); +}); + QUnit.test("suspend, then unsuspend a user", async assert => { const suspendUntilCombobox = selectKit(".suspend-until .combobox"); diff --git a/test/javascripts/acceptance/modal-test.js.es6 b/test/javascripts/acceptance/modal-test.js.es6 index 13725f4d6c..4e43be89bb 100644 --- a/test/javascripts/acceptance/modal-test.js.es6 +++ b/test/javascripts/acceptance/modal-test.js.es6 @@ -28,7 +28,7 @@ QUnit.test("modal", async function(assert) { await click(".login-button"); assert.ok(find(".d-modal:visible").length === 1, "modal should reappear"); - await keyEvent("#main-outlet", "keydown", 27); + await keyEvent("#main-outlet", "keyup", 27); assert.ok( find(".d-modal:visible").length === 0, "ESC should close the modal" @@ -47,7 +47,7 @@ QUnit.test("modal", async function(assert) { find(".d-modal:visible").length === 1, "modal should not disappear when you click outside" ); - await keyEvent("#main-outlet", "keydown", 27); + await keyEvent("#main-outlet", "keyup", 27); assert.ok( find(".d-modal:visible").length === 1, "ESC should not close the modal" @@ -61,7 +61,7 @@ QUnit.test("modal-keyboard-events", async function(assert) { await click(".toggle-admin-menu"); await click(".topic-admin-status-update button"); - await keyEvent(".d-modal", "keydown", 13); + await keyEvent(".d-modal", "keyup", 13); assert.ok( find("#modal-alert:visible").length === 1, @@ -72,7 +72,7 @@ QUnit.test("modal-keyboard-events", async function(assert) { "hitting Enter does not dismiss modal due to alert error" ); - await keyEvent("#main-outlet", "keydown", 27); + await keyEvent("#main-outlet", "keyup", 27); assert.ok( find(".d-modal:visible").length === 0, "ESC should close the modal" @@ -82,7 +82,7 @@ QUnit.test("modal-keyboard-events", async function(assert) { await click(".d-editor-button-bar .btn.link"); - await keyEvent(".d-modal", "keydown", 13); + await keyEvent(".d-modal", "keyup", 13); assert.ok( find(".d-modal:visible").length === 0, "modal should disappear on hitting Enter" From 6fe91bbbbb9a9bd076db6371c1f814f71b0ee711 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Thu, 5 Mar 2020 15:29:51 -1000 Subject: [PATCH 0098/1830] Revert "FEATURE: prevent accidental canceling when drafting penalties (#9105)" (#9122) This reverts commit 243284f998e213034f9f0c6b228f97f7c9834fdd. There are some issues in how the JS tests interact that I will need to figure out here before this can be merged. --- .../admin/mixins/penalty-controller.js.es6 | 24 +----------------- .../discourse/components/d-modal.js.es6 | 17 ++++++------- .../discourse/routes/application.js.es6 | 15 ++--------- config/locales/client.en.yml | 1 - .../acceptance/admin-suspend-user-test.js.es6 | 25 ------------------- test/javascripts/acceptance/modal-test.js.es6 | 10 ++++---- 6 files changed, 15 insertions(+), 77 deletions(-) diff --git a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 index f923710649..cb07e9d2ca 100644 --- a/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 +++ b/app/assets/javascripts/admin/mixins/penalty-controller.js.es6 @@ -1,7 +1,6 @@ import ModalFunctionality from "discourse/mixins/modal-functionality"; import { popupAjaxError } from "discourse/lib/ajax-error"; import Mixin from "@ember/object/mixin"; -import { next } from "@ember/runloop"; import { Promise } from "rsvp"; export default Mixin.create(ModalFunctionality, { @@ -12,7 +11,6 @@ export default Mixin.create(ModalFunctionality, { user: null, postId: null, successCallback: null, - confirmClose: false, resetModal() { this.setProperties({ @@ -23,30 +21,10 @@ export default Mixin.create(ModalFunctionality, { postEdit: null, postAction: "delete", before: null, - successCallback: null, - confirmClose: false + successCallback: null }); }, - beforeClose() { - // prompt a confirmation if we have unsaved content - if ( - (this.reason && this.reason.length > 1) || - (this.message && this.message.length > 1 && !this.confirmClose) - ) { - this.send("hideModal"); - bootbox.confirm(I18n.t("admin.user.confirm_cancel_penalty"), result => { - if (result) { - this.set("confirmClose", true); - this.send("closeModal"); - } else { - next(() => this.send("reopenModal")); - } - }); - return false; - } - }, - penalize(cb) { let before = this.before; let promise = before ? before() : Promise.resolve(); diff --git a/app/assets/javascripts/discourse/components/d-modal.js.es6 b/app/assets/javascripts/discourse/components/d-modal.js.es6 index eeae7edc3f..300a3e585c 100644 --- a/app/assets/javascripts/discourse/components/d-modal.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal.js.es6 @@ -31,16 +31,13 @@ export default Component.extend({ @on("didInsertElement") setUp() { - $("html").on("keyup.discourse-modal", e => { - //only respond to events when the modal is visible - if ($("#discourse-modal:visible").length > 0) { - if (e.which === 27 && this.dismissable) { - next(() => $(".modal-header button.modal-close").click()); - } + $("html").on("keydown.discourse-modal", e => { + if (e.which === 27 && this.dismissable) { + next(() => $(".modal-header button.modal-close").click()); + } - if (e.which === 13 && this.triggerClickOnEnter(e)) { - next(() => $(".modal-footer .btn-primary").click()); - } + if (e.which === 13 && this.triggerClickOnEnter(e)) { + next(() => $(".modal-footer .btn-primary").click()); } }); @@ -49,7 +46,7 @@ export default Component.extend({ @on("willDestroyElement") cleanUp() { - $("html").off("keyup.discourse-modal"); + $("html").off("keydown.discourse-modal"); this.appEvents.off("modal:body-shown", this, "_modalBodyShown"); }, diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 8dca333360..e877d8ceff 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -157,23 +157,12 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, { // Close the current modal, and destroy its state. closeModal() { + this.render("hide-modal", { into: "modal", outlet: "modalBody" }); + const route = getOwner(this).lookup("route:application"); let modalController = route.controllerFor("modal"); const controllerName = modalController.get("name"); - if (controllerName) { - const controller = getOwner(this).lookup( - `controller:${controllerName}` - ); - if (controller && controller.beforeClose) { - if (false === controller.beforeClose()) { - return; - } - } - } - - this.render("hide-modal", { into: "modal", outlet: "modalBody" }); - if (controllerName) { const controller = getOwner(this).lookup( `controller:${controllerName}` diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index c7705ab948..127c964d04 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4291,7 +4291,6 @@ en: threshold_reached: "Received too many bounces from that email." trust_level_change_failed: "There was a problem changing the user's trust level." suspend_modal_title: "Suspend User" - confirm_cancel_penalty: "Are you sure you want to discard the penalty?" trust_level_2_users: "Trust Level 2 Users" trust_level_3_requirements: "Trust Level 3 Requirements" trust_level_locked_tip: "trust level is locked, system will not promote or demote user" diff --git a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 b/test/javascripts/acceptance/admin-suspend-user-test.js.es6 index 936f7080bb..d9983848ca 100644 --- a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 +++ b/test/javascripts/acceptance/admin-suspend-user-test.js.es6 @@ -34,31 +34,6 @@ QUnit.test("suspend a user - cancel", async assert => { assert.equal(find(".suspend-user-modal:visible").length, 0); }); -QUnit.test("suspend a user - cancel with input", async assert => { - await visit("/admin/users/1234/regular"); - await click(".suspend-user"); - - assert.equal(find(".suspend-user-modal:visible").length, 1); - - await fillIn(".suspend-reason", "for breaking the rules"); - await fillIn(".suspend-message", "this is an email reason why"); - - await click(".d-modal-cancel"); - - assert.equal(find(".bootbox.modal:visible").length, 1); - - await click(".modal-footer .btn-default"); - assert.equal(find(".suspend-user-modal:visible").length, 1); - assert.equal( - find(".suspend-message")[0].value, - "this is an email reason why" - ); - - await click(".d-modal-cancel"); - await click(".modal-footer .btn-primary"); - assert.equal(find(".suspend-user-modal:visible").length, 0); -}); - QUnit.test("suspend, then unsuspend a user", async assert => { const suspendUntilCombobox = selectKit(".suspend-until .combobox"); diff --git a/test/javascripts/acceptance/modal-test.js.es6 b/test/javascripts/acceptance/modal-test.js.es6 index 4e43be89bb..13725f4d6c 100644 --- a/test/javascripts/acceptance/modal-test.js.es6 +++ b/test/javascripts/acceptance/modal-test.js.es6 @@ -28,7 +28,7 @@ QUnit.test("modal", async function(assert) { await click(".login-button"); assert.ok(find(".d-modal:visible").length === 1, "modal should reappear"); - await keyEvent("#main-outlet", "keyup", 27); + await keyEvent("#main-outlet", "keydown", 27); assert.ok( find(".d-modal:visible").length === 0, "ESC should close the modal" @@ -47,7 +47,7 @@ QUnit.test("modal", async function(assert) { find(".d-modal:visible").length === 1, "modal should not disappear when you click outside" ); - await keyEvent("#main-outlet", "keyup", 27); + await keyEvent("#main-outlet", "keydown", 27); assert.ok( find(".d-modal:visible").length === 1, "ESC should not close the modal" @@ -61,7 +61,7 @@ QUnit.test("modal-keyboard-events", async function(assert) { await click(".toggle-admin-menu"); await click(".topic-admin-status-update button"); - await keyEvent(".d-modal", "keyup", 13); + await keyEvent(".d-modal", "keydown", 13); assert.ok( find("#modal-alert:visible").length === 1, @@ -72,7 +72,7 @@ QUnit.test("modal-keyboard-events", async function(assert) { "hitting Enter does not dismiss modal due to alert error" ); - await keyEvent("#main-outlet", "keyup", 27); + await keyEvent("#main-outlet", "keydown", 27); assert.ok( find(".d-modal:visible").length === 0, "ESC should close the modal" @@ -82,7 +82,7 @@ QUnit.test("modal-keyboard-events", async function(assert) { await click(".d-editor-button-bar .btn.link"); - await keyEvent(".d-modal", "keyup", 13); + await keyEvent(".d-modal", "keydown", 13); assert.ok( find(".d-modal:visible").length === 0, "modal should disappear on hitting Enter" From 494379201d8e2927a08f7b3656eb7d1f2949d044 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Fri, 6 Mar 2020 12:57:12 +1100 Subject: [PATCH 0099/1830] DEV: attempt to stabilize flaky spec Spec was checking implementation when it did not need to, temp file was blank so optimized image should be blank --- spec/models/optimized_image_spec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/models/optimized_image_spec.rb b/spec/models/optimized_image_spec.rb index a7c8e2e352..e90029bec3 100644 --- a/spec/models/optimized_image_spec.rb +++ b/spec/models/optimized_image_spec.rb @@ -312,9 +312,10 @@ describe OptimizedImage do end end - context "when an error happened while generatign the thumbnail" do + context "when we have a bad file returned" do it "returns nil" do - OptimizedImage.expects(:resize).returns(false) + # tempfile is empty + # this can not be resized expect(OptimizedImage.create_for(s3_upload, 100, 200)).to eq(nil) end end From 29ccdf5d3527d61b655c28c8790c94a1bdd6dcba Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Fri, 6 Mar 2020 14:37:40 +1000 Subject: [PATCH 0100/1830] FIX: Show a nicer error if name/code missing for TOTP/Security Keys (#9124) Meta: https://meta.discourse.org/t/improve-error-message-when-not-including-name-setting-up-totp/143339 * when the user creates a TOTP second factor method we want to show them a nicer error if they forget to add a name or the code from the app, instead of the param missing error * also add a client-side check for this and for security key name, no need to bother the server if we can help it --- .../second-factor-add-security-key.js.es6 | 7 +++ .../controllers/second-factor-add-totp.js.es6 | 8 ++- .../modal/second-factor-add-security-key.hbs | 4 +- app/controllers/users_controller.rb | 8 ++- config/locales/client.en.yml | 2 + config/locales/server.en.yml | 2 + spec/requests/users_controller_spec.rb | 60 ++++++++++++++++++- .../acceptance/preferences-test.js.es6 | 40 +++++++++++-- 8 files changed, 120 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 index 54f41fc405..2cb03f968f 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-add-security-key.js.es6 @@ -53,6 +53,13 @@ export default Controller.extend(ModalFunctionality, { actions: { registerSecurityKey() { + if (!this.securityKeyName) { + this.set( + "errorMessage", + I18n.t("user.second_factor.security_key.name_required_error") + ); + return; + } const publicKeyCredentialCreationOptions = { challenge: Uint8Array.from(this.challenge, c => c.charCodeAt(0)), rp: { diff --git a/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 b/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 index eab4f2943f..10752e41c7 100644 --- a/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 +++ b/app/assets/javascripts/discourse/controllers/second-factor-add-totp.js.es6 @@ -45,7 +45,13 @@ export default Controller.extend(ModalFunctionality, { }, enableSecondFactor() { - if (!this.secondFactorToken) return; + if (!this.secondFactorToken || !this.secondFactorName) { + this.set( + "errorMessage", + I18n.t("user.second_factor.totp.name_and_code_required_error") + ); + return; + } this.set("loading", true); this.model diff --git a/app/assets/javascripts/discourse/templates/modal/second-factor-add-security-key.hbs b/app/assets/javascripts/discourse/templates/modal/second-factor-add-security-key.hbs index d63b5fe8eb..36ede3f634 100644 --- a/app/assets/javascripts/discourse/templates/modal/second-factor-add-security-key.hbs +++ b/app/assets/javascripts/discourse/templates/modal/second-factor-add-security-key.hbs @@ -16,7 +16,7 @@
- {{input value=securityKeyName id='test' placeholder='security key name'}} + {{input value=securityKeyName id='security-key-name' placeholder='security key name'}}
@@ -24,7 +24,7 @@
{{#unless webauthnUnsupported}} {{d-button - class="btn-primary add-totp" + class="btn-primary add-security-key" action=(action "registerSecurityKey") label="user.second_factor.security_key.register"}} {{/unless}} diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e96a79c953..33e7bdce6c 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1211,8 +1211,12 @@ class UsersController < ApplicationController end def enable_second_factor_totp - params.require(:second_factor_token) - params.require(:name) + if params[:second_factor_token].blank? + return render json: failed_json.merge(error: I18n.t("login.missing_second_factor_code")) + end + if params[:name].blank? + return render json: failed_json.merge(error: I18n.t("login.missing_second_factor_name")) + end auth_token = params[:second_factor_token] totp_data = secure_session["staged-totp-#{current_user.id}"] diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 127c964d04..a18720a293 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1023,6 +1023,7 @@ en: title: "Token-Based Authenticators" add: "New Authenticator" default_name: "My Authenticator" + name_and_code_required_error: "You must provide a name and the code from your authenticator app." security_key: register: "Register" title: "Security Keys" @@ -1033,6 +1034,7 @@ en: edit: "Edit Security Key" edit_description: "Security Key Name" delete: "Delete" + name_required_error: "You must provide a name for your security key." change_about: title: "Change About Me" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index c4db42fb1c..3705e98f01 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2381,6 +2381,8 @@ en: second_factor_backup_title: "Two Factor Backup Code" invalid_second_factor_code: "Invalid authentication code. Each code can only be used once." invalid_security_key: "Invalid security key." + missing_second_factor_name: "Please provide a name." + missing_second_factor_code: "Please provide a code." second_factor_toggle: totp: "Use an authenticator app or security key instead" backup_code: "Use a backup code instead" diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index ed28cab650..13aebdfd2f 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -3522,6 +3522,58 @@ describe UsersController do end end + describe "#enable_second_factor_totp" do + before do + sign_in(user) + end + + def create_totp + stub_secure_session_confirmed + post "/users/create_second_factor_totp.json" + end + + it "creates a totp for the user successfully" do + create_totp + staged_totp_key = read_secure_session["staged-totp-#{user.id}"] + token = ROTP::TOTP.new(staged_totp_key).now + + post "/users/enable_second_factor_totp.json", params: { name: "test", second_factor_token: token } + + expect(response.status).to eq(200) + expect(user.user_second_factors.count).to eq(1) + end + + context "when an incorrect token is provided" do + before do + create_totp + post "/users/enable_second_factor_totp.json", params: { name: "test", second_factor_token: "123456" } + end + it "shows a helpful error message to the user" do + expect(JSON.parse(response.body)['error']).to eq(I18n.t("login.invalid_second_factor_code")) + end + end + + context "when a name is not provided" do + before do + create_totp + post "/users/enable_second_factor_totp.json", params: { second_factor_token: "123456" } + end + it "shows a helpful error message to the user" do + expect(JSON.parse(response.body)['error']).to eq(I18n.t("login.missing_second_factor_name")) + end + end + + context "when a token is not provided" do + before do + create_totp + post "/users/enable_second_factor_totp.json", params: { name: "test" } + end + it "shows a helpful error message to the user" do + expect(JSON.parse(response.body)['error']).to eq(I18n.t("login.missing_second_factor_code")) + end + end + end + describe '#update_second_factor' do let(:user_second_factor) { Fabricate(:user_second_factor_totp, user: user) } @@ -3554,7 +3606,7 @@ describe UsersController do context 'when token is valid' do before do - ApplicationController.any_instance.stubs(:secure_session).returns("confirmed-password-#{user.id}" => "true") + stub_secure_session_confirmed end it 'should allow second factor for the user to be renamed' do put "/users/second_factor.json", params: { @@ -4062,7 +4114,11 @@ describe UsersController do def create_second_factor_security_key sign_in(user) - UsersController.any_instance.stubs(:secure_session_confirmed?).returns(true) + stub_secure_session_confirmed post "/u/create_second_factor_security_key.json" end + + def stub_secure_session_confirmed + UsersController.any_instance.stubs(:secure_session_confirmed?).returns(true) + end end diff --git a/test/javascripts/acceptance/preferences-test.js.es6 b/test/javascripts/acceptance/preferences-test.js.es6 index ce5d8f68b1..c651c67802 100644 --- a/test/javascripts/acceptance/preferences-test.js.es6 +++ b/test/javascripts/acceptance/preferences-test.js.es6 @@ -20,6 +20,16 @@ acceptance("User Preferences", { }); }); + server.post("/u/create_second_factor_security_key.json", () => { + return helper.response({ + challenge: + "a6d393d12654c130b2273e68ca25ca232d1d7f4c2464c2610fb8710a89d4", + rp_id: "localhost", + rp_name: "Discourse", + supported_algoriths: [-7, -257] + }); + }); + server.post("/u/enable_second_factor_totp.json", () => { return helper.response({ error: "invalid token" }); }); @@ -211,7 +221,7 @@ QUnit.test("connected accounts", async assert => { .indexOf("Connect") > -1; }); -QUnit.test("second factor", async assert => { +QUnit.test("second factor totp", async assert => { await visit("/u/eviltrout/preferences/second-factor"); assert.ok(exists("#password"), "it has a password input"); @@ -223,14 +233,36 @@ QUnit.test("second factor", async assert => { await click(".new-totp"); assert.ok(exists("#test-qr"), "shows qr code"); - await fillIn("#second-factor-token", "111111"); await click(".add-totp"); assert.ok( find(".alert-error") .html() - .indexOf("invalid token") > -1, - "shows server validation error message" + .indexOf("provide a name and the code") > -1, + "shows name/token missing error message" + ); +}); + +QUnit.test("second factor security keys", async assert => { + await visit("/u/eviltrout/preferences/second-factor"); + + assert.ok(exists("#password"), "it has a password input"); + + await fillIn("#password", "secrets"); + await click(".user-preferences .btn-primary"); + assert.notOk(exists("#password"), "it hides the password input"); + + await click(".new-security-key"); + assert.ok(exists("#security-key-name"), "shows security key name input"); + + fillIn("#security-key-name", ""); + await click(".add-security-key"); + + assert.ok( + find(".alert-error") + .html() + .indexOf("provide a name") > -1, + "shows name missing error message" ); }); From ff62911a89d721ebec1716990c5e407e572d8960 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Fri, 6 Mar 2020 12:23:22 +0000 Subject: [PATCH 0101/1830] FEATURE: New route for loading multiple user cards simultaneously (#9078) Introduces `/user-cards.json` Also allows the client-side user model to be passed an existing promise when loading, so that multiple models can share the same AJAX request --- .../javascripts/discourse/models/user.js.es6 | 6 +++- app/controllers/users_controller.rb | 24 ++++++++++++++++ config/routes.rb | 2 ++ spec/requests/users_controller_spec.rb | 28 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 6927676805..84c2765f6f 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -536,8 +536,12 @@ const User = RestModel.extend({ const user = this; return PreloadStore.getAndRemove(`user_${user.get("username")}`, () => { - const useCardRoute = options && options.forCard; + if (options && options.existingRequest) { + // Existing ajax request has been passed, use it + return options.existingRequest; + } + const useCardRoute = options && options.forCard; if (options) delete options.forCard; const path = useCardRoute diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 33e7bdce6c..5b7bbc7022 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -99,6 +99,30 @@ class UsersController < ApplicationController show(for_card: true) end + def cards + return redirect_to path('/login') if SiteSetting.hide_user_profiles_from_public && !current_user + + user_ids = params.require(:user_ids).split(",").map(&:to_i) + raise Discourse::InvalidParameters.new(:user_ids) if user_ids.length > 50 + + users = User.where(id: user_ids).includes(:user_option, + :user_stat, + :default_featured_user_badges, + :user_profile, + :card_background_upload, + :primary_group, + :primary_email + ) + + users = users.filter { |u| guardian.can_see_profile?(u) } + + preload_fields = User.whitelisted_user_custom_fields(guardian) + UserField.all.pluck(:id).map { |fid| "#{User::USER_FIELD_PREFIX}#{fid}" } + User.preload_custom_fields(users, preload_fields) + User.preload_recent_time_read(users) + + render json: users, each_serializer: UserCardSerializer + end + def badges raise Discourse::NotFound unless SiteSetting.enable_badges? show diff --git a/config/routes.rb b/config/routes.rb index 8fd2d19727..38047b91eb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -367,6 +367,8 @@ Discourse::Application.routes.draw do get "user_preferences" => "users#user_preferences_redirect" get ".well-known/change-password", to: redirect(relative_url_root + 'my/preferences/account', status: 302) + get "user-cards" => "users#cards", format: :json + %w{users u}.each_with_index do |root_path, index| get "#{root_path}" => "users#index", constraints: { format: 'html' } diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 13aebdfd2f..7a15170e38 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -3052,6 +3052,34 @@ describe UsersController do end end + describe "#cards" do + fab!(:user) { Discourse.system_user } + fab!(:user2) { Fabricate(:user) } + + it "returns success" do + get "/user-cards.json?user_ids=#{user.id},#{user2.id}" + expect(response.status).to eq(200) + parsed = JSON.parse(response.body)["users"] + + expect(parsed.map { |u| u["username"] }).to contain_exactly(user.username, user2.username) + end + + it "should redirect to login page for anonymous user when profiles are hidden" do + SiteSetting.hide_user_profiles_from_public = true + get "/user-cards.json?user_ids=#{user.id},#{user2.id}" + expect(response).to redirect_to '/login' + end + + it "does not include hidden profiles" do + user2.user_option.update(hide_profile_and_presence: true) + get "/user-cards.json?user_ids=#{user.id},#{user2.id}" + expect(response.status).to eq(200) + parsed = JSON.parse(response.body)["users"] + + expect(parsed.map { |u| u["username"] }).to contain_exactly(user.username) + end + end + describe '#badges' do it "renders fine by default" do get "/u/#{user.username}/badges" From 665d8564d80902a3f9febe837466988ceb3fa33b Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Fri, 6 Mar 2020 11:19:34 -0300 Subject: [PATCH 0102/1830] DEV: Use the updated version of our mousetrap fork (#9111) --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 2ff91e0b49..005db309fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1915,8 +1915,8 @@ moment@^2.10.2: integrity sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y= "mousetrap@https://github.com/discourse/mousetrap#firefox-alt-key": - version "1.6.3" - resolved "https://github.com/discourse/mousetrap#0d41aa7b173abfb83a6bec3ad39a6a708bc49108" + version "1.6.5" + resolved "https://github.com/discourse/mousetrap#cc8e2c0b9229e1a01ce68de4f339b6fd35503041" ms@2.0.0: version "2.0.0" From a5f61729e0593804051047df86f1a8e1d271794a Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 6 Mar 2020 08:49:28 -0500 Subject: [PATCH 0103/1830] Revert "Revert "FIX: Don't allow people to clear the upload bucket while it's enabled"" This reverts commit d4fc76b335d012275b06b7ce80d0c1b98f9db33d. --- lib/site_settings/validations.rb | 2 ++ spec/lib/site_settings/validations_spec.rb | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/lib/site_settings/validations.rb b/lib/site_settings/validations.rb index 56987b0dfe..0bf13f7606 100644 --- a/lib/site_settings/validations.rb +++ b/lib/site_settings/validations.rb @@ -143,6 +143,8 @@ module SiteSettings::Validations def validate_s3_upload_bucket(new_val) validate_bucket_setting("s3_upload_bucket", new_val, SiteSetting.s3_backup_bucket) + + validate_error(:s3_upload_bucket_is_required, setting_name: 's3_upload_bucket') if new_val.blank? && SiteSetting.enable_s3_uploads? end def validate_s3_backup_bucket(new_val) diff --git a/spec/lib/site_settings/validations_spec.rb b/spec/lib/site_settings/validations_spec.rb index 7f346d4d5c..69ab73920b 100644 --- a/spec/lib/site_settings/validations_spec.rb +++ b/spec/lib/site_settings/validations_spec.rb @@ -103,6 +103,15 @@ describe SiteSettings::Validations do SiteSetting.s3_backup_bucket = "my-awesome-bucket/foo" expect { validate("my-awesome-bucket/foo/uploads") }.to raise_error(Discourse::InvalidParameters, error_message) end + + it "cannot be made blank unless the setting is false" do + SiteSetting.s3_backup_bucket = "really-real-cool-bucket" + SiteSetting.enable_s3_uploads = true + + expect { validate("") }.to raise_error(Discourse::InvalidParameters) + SiteSetting.enable_s3_uploads = false + validate("") + end end end From 91682408e0fc47e0c2d72a993988797eb2d095ac Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 6 Mar 2020 09:35:38 -0500 Subject: [PATCH 0104/1830] Remove very bad tests --- spec/models/admin_dashboard_problem_spec.rb | 104 -------------------- 1 file changed, 104 deletions(-) diff --git a/spec/models/admin_dashboard_problem_spec.rb b/spec/models/admin_dashboard_problem_spec.rb index c61b346224..84b596e17b 100644 --- a/spec/models/admin_dashboard_problem_spec.rb +++ b/spec/models/admin_dashboard_problem_spec.rb @@ -194,110 +194,6 @@ describe AdminDashboardData do end end - describe 's3_config_check' do - shared_examples 'problem detection for s3-dependent setting' do - subject { described_class.new.s3_config_check } - let(:access_keys) { [:s3_access_key_id, :s3_secret_access_key] } - let(:all_cred_keys) { access_keys + [:s3_use_iam_profile] } - let(:all_setting_keys) { all_cred_keys + [bucket_key] } - - def all_setting_permutations(keys) - ['a', ''].repeated_permutation(keys.size) do |*values| - hash = Hash[keys.zip(values)] - hash.each do |key, value| - SiteSetting.set(key, value) - end - yield hash - end - end - - context 'when setting is enabled' do - before do - all_setting_keys.each { |key| SiteSetting.set(key, 'foo') } - SiteSetting.set(setting[:key], setting[:enabled_value]) - SiteSetting.set(bucket_key, bucket_value) - end - - context 'when bucket is blank' do - let(:bucket_value) { '' } - - it "always returns a string" do - all_setting_permutations(all_cred_keys) do - expect(subject).to_not be_nil - end - end - end - - context 'when bucket is filled in' do - let(:bucket_value) { 'a' } - before do - SiteSetting.s3_use_iam_profile = use_iam_profile - end - - context 'when using iam profile' do - let(:use_iam_profile) { true } - - it 'always returns nil' do - all_setting_permutations(access_keys) do - expect(subject).to be_nil - end - end - end - - context 'when not using iam profile' do - let(:use_iam_profile) { false } - - it 'returns nil only if both access key fields are filled in' do - all_setting_permutations(access_keys) do |settings| - if settings.values.all? - expect(subject).to be_nil - else - expect(subject).to_not be_nil - end - end - end - end - end - end - - context 'when setting is not enabled' do - before do - SiteSetting.set(setting[:key], setting[:disabled_value]) - end - - it "always returns nil" do - all_setting_permutations(all_setting_keys) do - expect(subject).to be_nil - end - end - end - end - - describe 'uploads' do - let(:setting) do - { - key: :enable_s3_uploads, - enabled_value: true, - disabled_value: false - } - end - let(:bucket_key) { :s3_upload_bucket } - include_examples 'problem detection for s3-dependent setting' - end - - describe 'backups' do - let(:setting) do - { - key: :backup_location, - enabled_value: BackupLocationSiteSetting::S3, - disabled_value: BackupLocationSiteSetting::LOCAL - } - end - let(:bucket_key) { :s3_backup_bucket } - include_examples 'problem detection for s3-dependent setting' - end - end - describe 'force_https_check' do subject { described_class.new(check_force_https: true).force_https_check } From a24f51278a954ebd2d0da9580580caf57c36b2ee Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 6 Mar 2020 17:35:18 +0100 Subject: [PATCH 0105/1830] DEV: enforces link-rel-noopener linting rule (#8936) * DEV: enforces link-rel-noopener linting rule * oops * better syntax --- .template-lintrc.js | 3 ++- .../javascripts/admin/templates/badges-index.hbs | 2 +- .../admin/templates/customize-themes-edit.hbs | 12 +++++++----- .../admin/templates/customize-themes-index.hbs | 2 +- .../admin/templates/customize-themes-show.hbs | 6 +++--- .../admin/templates/modal/admin-install-theme.hbs | 4 ++-- .../admin/templates/modal/admin-theme-item.hbs | 2 +- .../javascripts/admin/templates/plugins-index.hbs | 2 +- .../javascripts/admin/templates/version-checks.hbs | 2 +- .../discourse/templates/components/backup-codes.hbs | 1 + .../discourse/templates/components/ip-lookup.hbs | 2 +- .../templates/components/user-card-contents.hbs | 3 ++- .../discourse/templates/review-topics.hbs | 2 +- .../discourse/templates/user-invited-show.hbs | 2 +- app/assets/javascripts/discourse/templates/user.hbs | 3 ++- .../javascripts/discourse/templates/user/summary.hbs | 3 ++- .../wizard/templates/components/popular-themes.hbs | 2 +- 17 files changed, 30 insertions(+), 23 deletions(-) diff --git a/.template-lintrc.js b/.template-lintrc.js index 5731778fc0..3a85b721b0 100644 --- a/.template-lintrc.js +++ b/.template-lintrc.js @@ -6,6 +6,7 @@ module.exports = { "self-closing-void-elements": true, "table-groups": true, "style-concatenation": true, - "no-invalid-interactive": true + "no-invalid-interactive": true, + "link-rel-noopener": true } }; diff --git a/app/assets/javascripts/admin/templates/badges-index.hbs b/app/assets/javascripts/admin/templates/badges-index.hbs index a3296fc23e..fd08e67279 100644 --- a/app/assets/javascripts/admin/templates/badges-index.hbs +++ b/app/assets/javascripts/admin/templates/badges-index.hbs @@ -5,7 +5,7 @@

{{i18n 'admin.badges.badge_intro.title'}}

{{#each badgeIntroLinks as |link|}} - + {{d-icon link.icon}} {{I18n link.text}} diff --git a/app/assets/javascripts/admin/templates/customize-themes-edit.hbs b/app/assets/javascripts/admin/templates/customize-themes-edit.hbs index d17ab8d2f3..5fdaa76885 100644 --- a/app/assets/javascripts/admin/templates/customize-themes-edit.hbs +++ b/app/assets/javascripts/admin/templates/customize-themes-edit.hbs @@ -2,20 +2,22 @@

{{i18n 'admin.customize.theme.edit_css_html'}} {{#link-to showRouteName model.id replace=true}}{{model.name}}{{/link-to}}

- {{admin-theme-editor - theme=model - editRouteName=editRouteName + {{admin-theme-editor + theme=model + editRouteName=editRouteName currentTargetName=currentTargetName fieldName=fieldName fieldAdded=(action 'fieldAdded') maximized=maximized onlyOverriddenChanged=(action 'onlyOverriddenChanged') }} - +
{{#each externalResources as |resource|}} - + {{d-icon resource.icon}} {{I18n resource.key}} diff --git a/app/assets/javascripts/admin/templates/customize-themes-show.hbs b/app/assets/javascripts/admin/templates/customize-themes-show.hbs index de6b46da74..2687c6b692 100644 --- a/app/assets/javascripts/admin/templates/customize-themes-show.hbs +++ b/app/assets/javascripts/admin/templates/customize-themes-show.hbs @@ -206,7 +206,7 @@
    {{#each model.uploads as |upload|}}
  • - ${{upload.name}}: {{upload.filename}} + ${{upload.name}}: {{upload.filename}} {{d-button action=(action "removeUpload") actionParam=upload class="second btn-default btn-default cancel-edit" icon="times"}} @@ -241,8 +241,8 @@
{{/if}} - {{d-icon 'desktop'}}{{i18n 'admin.customize.theme.preview'}} - {{d-icon "download"}} {{i18n 'admin.export_json.button_text'}} + {{d-icon 'desktop'}}{{i18n 'admin.customize.theme.preview'}} + {{d-icon "download"}} {{i18n 'admin.export_json.button_text'}} {{d-button action=(action "switchType") label="admin.customize.theme.convert" icon=convertIcon class="btn-default btn-normal" title=convertTooltip}} diff --git a/app/assets/javascripts/admin/templates/modal/admin-install-theme.hbs b/app/assets/javascripts/admin/templates/modal/admin-install-theme.hbs index 7307abb411..eec9151f90 100644 --- a/app/assets/javascripts/admin/templates/modal/admin-install-theme.hbs +++ b/app/assets/javascripts/admin/templates/modal/admin-install-theme.hbs @@ -11,7 +11,7 @@ {{#each themes as |theme|}}
{{number model.todayCount}}
diff --git a/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs b/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs index 4b4a406c59..a1e64441f9 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs @@ -2,7 +2,7 @@ {{#if report.icon}} {{d-icon report.icon}} {{/if}} - {{report.title}} + {{report.title}} {{number report.todayCount}} diff --git a/app/assets/javascripts/admin/templates/components/admin-report-inline-table.hbs b/app/assets/javascripts/admin/templates/components/admin-report-inline-table.hbs index 70138f829d..76c8eacb0b 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-inline-table.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-inline-table.hbs @@ -1,6 +1,6 @@
{{#each model.data as |data|}} - + {{#if data.icon}} {{d-icon data.icon}} diff --git a/app/assets/javascripts/admin/templates/components/admin-report-storage-stats.hbs b/app/assets/javascripts/admin/templates/components/admin-report-storage-stats.hbs index 054b91d707..fbb9f80a64 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-storage-stats.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-storage-stats.hbs @@ -1,7 +1,7 @@ {{#if showBackupStats}}

- {{d-icon "archive"}} {{i18n "admin.dashboard.backups"}} + {{d-icon "archive"}} {{i18n "admin.dashboard.backups"}}

{{#if backupStats.free_bytes}} diff --git a/app/assets/javascripts/admin/templates/components/admin-report-table.hbs b/app/assets/javascripts/admin/templates/components/admin-report-table.hbs index 6c7838e872..f42189eb9a 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-table.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-table.hbs @@ -24,7 +24,7 @@ {{#if showTotalForSample}} - + {{i18n 'admin.dashboard.reports.totals_for_sample'}} diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs index cb0f333bb0..0c7009cc82 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs @@ -18,17 +18,17 @@ {{#unless showNotFoundError}}

  • - + {{model.title}} {{#if model.description}} {{#if model.description_link}} - + {{d-icon "question-circle"}} {{else}} - + {{d-icon "question-circle"}} {{/if}} @@ -40,7 +40,7 @@ {{#if shouldDisplayTrend}}
    - + {{#if model.average}} {{number model.currentAverage}}{{#if model.percent}}%{{/if}} {{else}} @@ -77,7 +77,7 @@
    {{d-icon "chart-pie"}} {{#if model.reportUrl}} - + {{#if model.title}} {{model.title}} — diff --git a/app/assets/javascripts/admin/templates/components/admin-theme-editor.hbs b/app/assets/javascripts/admin/templates/components/admin-theme-editor.hbs index bf9d2fd3cb..ad669f4d3d 100644 --- a/app/assets/javascripts/admin/templates/components/admin-theme-editor.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-theme-editor.hbs @@ -25,7 +25,7 @@ {{d-icon (if showAdvanced "angle-double-left" "angle-double-right")}} diff --git a/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs b/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs index ce952f3ec7..11977f1398 100644 --- a/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-web-hook-event.hbs @@ -1,5 +1,5 @@
    - {{model.status}} + {{model.status}}
    {{model.id}}
    {{createdAt}}
    diff --git a/app/assets/javascripts/admin/templates/components/flag-user.hbs b/app/assets/javascripts/admin/templates/components/flag-user.hbs index 26087789e5..a6a4ce0f95 100644 --- a/app/assets/javascripts/admin/templates/components/flag-user.hbs +++ b/app/assets/javascripts/admin/templates/components/flag-user.hbs @@ -7,7 +7,7 @@ {{#link-to 'adminUser' user.id user.username class="flag-user-username"}} {{user.username}} {{/link-to}} -
    +
    {{format-age date}}
    diff --git a/app/assets/javascripts/admin/templates/components/install-theme-item.hbs b/app/assets/javascripts/admin/templates/components/install-theme-item.hbs index ed4ddd242f..2697ffe8b9 100644 --- a/app/assets/javascripts/admin/templates/components/install-theme-item.hbs +++ b/app/assets/javascripts/admin/templates/components/install-theme-item.hbs @@ -1,5 +1,5 @@ {{radio-button name="install-items" id=value value=value selection=selection}} -
  • {{#if user.showBookmarks}}
  • - {{#link-to 'userActivity.bookmarksWithReminders'}}{{i18n 'user_action_groups.3'}}{{/link-to}} + {{#link-to "userActivity.bookmarks"}}{{i18n "user_action_groups.3"}}{{/link-to}}
  • {{/if}} {{plugin-outlet diff --git a/app/assets/javascripts/discourse/app/templates/user/summary.hbs b/app/assets/javascripts/discourse/app/templates/user/summary.hbs index ff9c7520f9..ddd89595c5 100644 --- a/app/assets/javascripts/discourse/app/templates/user/summary.hbs +++ b/app/assets/javascripts/discourse/app/templates/user/summary.hbs @@ -27,7 +27,7 @@ {{#if model.bookmark_count}}
  • - {{#link-to "userActivity.bookmarksWithReminders"}} + {{#link-to "userActivity.bookmarks"}} {{user-stat value=model.bookmark_count label="user.summary.bookmark_count"}} {{/link-to}}
  • diff --git a/app/assets/javascripts/discourse/app/widgets/quick-access-bookmarks.js b/app/assets/javascripts/discourse/app/widgets/quick-access-bookmarks.js index 787fce384d..3782b3e67c 100644 --- a/app/assets/javascripts/discourse/app/widgets/quick-access-bookmarks.js +++ b/app/assets/javascripts/discourse/app/widgets/quick-access-bookmarks.js @@ -16,7 +16,7 @@ createWidgetFrom(QuickAccessPanel, "quick-access-bookmarks", { }, showAllHref() { - return `${this.attrs.path}/activity/bookmarks-with-reminders`; + return `${this.attrs.path}/activity/bookmarks`; }, emptyStatePlaceholderItem() { diff --git a/app/assets/javascripts/discourse/app/widgets/user-menu.js b/app/assets/javascripts/discourse/app/widgets/user-menu.js index 08792c4130..6f4b5c323c 100644 --- a/app/assets/javascripts/discourse/app/widgets/user-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/user-menu.js @@ -62,7 +62,7 @@ createWidget("user-menu-links", { label: "user.bookmarks", className: "user-bookmarks-link", icon: "bookmark", - href: `${this.attrs.path}/activity/bookmarks-with-reminders` + href: `${this.attrs.path}/activity/bookmarks` }; }, diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb index 072c54beaf..5e9a1f38a5 100644 --- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb +++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/new_user_narrative.rb @@ -238,7 +238,7 @@ module DiscourseNarrativeBot return unless @post.user_id == self.discobot_user.id profile_page_url = url_helpers(:user_url, username: @user.username) - bookmark_url = "#{profile_page_url}/activity/bookmarks-with-reminders" + bookmark_url = "#{profile_page_url}/activity/bookmarks" raw = <<~RAW #{I18n.t("#{I18N_KEY}.bookmark.reply", i18n_post_args(bookmark_url: bookmark_url))} diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb index d875de3b10..ce65b15463 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb @@ -256,7 +256,7 @@ describe DiscourseNarrativeBot::NewUserNarrative do profile_page_url = "#{Discourse.base_url}/u/#{user.username}" expected_raw = <<~RAW - #{I18n.t('discourse_narrative_bot.new_user_narrative.bookmark.reply', bookmark_url: "#{profile_page_url}/activity/bookmarks-with-reminders", base_uri: '')} + #{I18n.t('discourse_narrative_bot.new_user_narrative.bookmark.reply', bookmark_url: "#{profile_page_url}/activity/bookmarks", base_uri: '')} #{I18n.t('discourse_narrative_bot.new_user_narrative.onebox.instructions', base_uri: '')} RAW diff --git a/test/javascripts/acceptance/user-bookmarks-test.js b/test/javascripts/acceptance/user-bookmarks-test.js index e965510129..3a276810c8 100644 --- a/test/javascripts/acceptance/user-bookmarks-test.js +++ b/test/javascripts/acceptance/user-bookmarks-test.js @@ -15,13 +15,13 @@ acceptance("User's bookmarks", { }); test("listing user bookmarks", async assert => { - await visit("/u/eviltrout/activity/bookmarks-with-reminders"); + await visit("/u/eviltrout/activity/bookmarks"); assert.ok(find(".bookmark-list-item").length); }); test("removing a bookmark", async assert => { - await visit("/u/eviltrout/activity/bookmarks-with-reminders"); + await visit("/u/eviltrout/activity/bookmarks"); const dropdown = selectKit(".bookmark-actions-dropdown"); await dropdown.expand(); @@ -44,7 +44,7 @@ test("listing users bookmarks - no bookmarks", async assert => { } ]); - await visit("/u/eviltrout/activity/bookmarks-with-reminders"); + await visit("/u/eviltrout/activity/bookmarks"); assert.equal(find(".alert.alert-info").text(), "no bookmarks"); }); From 24b9759c602b025e269ebc29aa77447c08b290e3 Mon Sep 17 00:00:00 2001 From: Kris Date: Tue, 28 Apr 2020 21:14:29 -0400 Subject: [PATCH 0839/1830] UX: fix dashboard version panel width by removing extra wrapper --- app/assets/javascripts/admin/templates/dashboard.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/templates/dashboard.hbs b/app/assets/javascripts/admin/templates/dashboard.hbs index cbbd34b4b2..05296f4d7b 100644 --- a/app/assets/javascripts/admin/templates/dashboard.hbs +++ b/app/assets/javascripts/admin/templates/dashboard.hbs @@ -3,7 +3,7 @@ {{#if showVersionChecks}}
    - {{version-checks versionCheck=versionCheck}} + {{version-checks versionCheck=versionCheck tagName=""}}
    {{/if}} From 5503eba9240664122d5b4cb41a6ec619b4425e5c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 11:10:57 +0800 Subject: [PATCH 0840/1830] DEV: Add env in dev to support verbose query log. --- config/environments/development.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/environments/development.rb b/config/environments/development.rb index ffada27d98..2a612c7164 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -39,6 +39,10 @@ Discourse::Application.configure do config.log_level = ENV['DISCOURSE_DEV_LOG_LEVEL'] if ENV['DISCOURSE_DEV_LOG_LEVEL'] + if ENV['RAILS_VERBOSE_QUERY_LOGS'] + config.active_record.verbose_query_logs = true + end + if defined?(BetterErrors) BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP'] From 301a0fa54eefb97f891b03c95de4bf4fb7f5cb4a Mon Sep 17 00:00:00 2001 From: Alan Guo Xiang Tan Date: Wed, 29 Apr 2020 12:48:55 +0800 Subject: [PATCH 0841/1830] FEATURE: Redesign discourse-presence to track state on the client side. (#9487) Before this commit, the presence state of users were stored on the server side and any updates to the state meant we had to publish the entire state to the clients. Also, the way the state of users were stored on the server side meant we didn't have a way to differentiate between replying users and whispering users. In this redesign, we decided to move the tracking of users state to the client side and have the server publish client events instead. As a result of this change, we're able to remove the number of opened connections needed to track presence and also reduce the payload that is sent for each event. At the same time, we've also improved on the restrictions when publishing message_bus messages. Users that do not have permission to see certain events will not receive messages for those events. --- .../composer-presence-display.js.es6 | 151 ++--- .../components/topic-presence-display.js.es6 | 54 +- .../discourse/lib/presence-manager.js.es6 | 201 ++++++ .../components/composer-presence-display.hbs | 4 +- .../connectors/composer-fields/presence.hbs | 1 + .../topic-above-footer-buttons/presence.hbs | 2 +- .../initializers/discourse-presence.js.es6 | 42 ++ .../discourse-presence/config/settings.yml | 1 + plugins/discourse-presence/plugin.rb | 248 ++++---- .../spec/presence_manager_spec.rb | 108 ---- .../spec/requests/presence_controller_spec.rb | 590 +++++++++++++----- 11 files changed, 859 insertions(+), 543 deletions(-) create mode 100644 plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 create mode 100644 plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 delete mode 100644 plugins/discourse-presence/spec/presence_manager_spec.rb diff --git a/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 index 1e78297376..e6a366087b 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 @@ -1,12 +1,11 @@ -import { cancel, debounce, once } from "@ember/runloop"; import Component from "@ember/component"; -import { equal, gt } from "@ember/object/computed"; -import { Promise } from "rsvp"; -import { ajax } from "discourse/lib/ajax"; -import computed, { observes, on } from "discourse-common/utils/decorators"; - -export const keepAliveDuration = 10000; -export const bufferTime = 3000; +import { cancel } from "@ember/runloop"; +import { equal, gt, readOnly } from "@ember/object/computed"; +import discourseComputed, { + observes, + on +} from "discourse-common/utils/decorators"; +import { REPLYING, CLOSED, EDITING } from "../lib/presence-manager"; export default Component.extend({ // Passed in variables @@ -15,115 +14,67 @@ export default Component.extend({ topic: null, reply: null, title: null, + isWhispering: null, - // Internal variables - previousState: null, - currentState: null, - presenceUsers: null, - channel: null, - + presenceManager: readOnly("topic.presenceManager"), + users: readOnly("presenceManager.users"), + editingUsers: readOnly("presenceManager.editingUsers"), isReply: equal("action", "reply"), - shouldDisplay: gt("users.length", 0), @on("didInsertElement") - composerOpened() { - this._lastPublish = new Date(); - once(this, "updateState"); + subscribe() { + this.presenceManager && this.presenceManager.subscribe(); }, - @observes("action", "post.id", "topic.id") - composerStateChanged() { - once(this, "updateState"); + @discourseComputed( + "post.id", + "editingUsers.@each.last_seen", + "users.@each.last_seen" + ) + presenceUsers(postId, editingUsers, users) { + if (postId) { + return editingUsers.filterBy("post_id", postId); + } else { + return users; + } }, + shouldDisplay: gt("presenceUsers.length", 0), + @observes("reply", "title") typing() { - if (new Date() - this._lastPublish > keepAliveDuration) { - this.publish({ current: this.currentState }); + if (this.presenceManager) { + const postId = this.get("post.id"); + + this._throttle = this.presenceManager.throttlePublish( + postId ? EDITING : REPLYING, + this.whisper, + postId + ); + } + }, + + @observes("whisper") + cancelThrottle() { + this._cancelThrottle(); + }, + + @observes("post.id") + stopEditing() { + if (this.presenceManager && !this.get("post.id")) { + this.presenceManager.publish(CLOSED, this.whisper); } }, @on("willDestroyElement") composerClosing() { - this.publish({ previous: this.currentState }); - cancel(this._pingTimer); - cancel(this._clearTimer); - }, - - updateState() { - let state = null; - const action = this.action; - - if (action === "reply" || action === "edit") { - state = { action }; - if (action === "reply") state.topic_id = this.get("topic.id"); - if (action === "edit") state.post_id = this.get("post.id"); + if (this.presenceManager) { + this._cancelThrottle(); + this.presenceManager.publish(CLOSED, this.whisper); } - - this.set("previousState", this.currentState); - this.set("currentState", state); }, - @observes("currentState") - currentStateChanged() { - if (this.channel) { - this.messageBus.unsubscribe(this.channel); - this.set("channel", null); - } - - this.clear(); - - if (!["reply", "edit"].includes(this.action)) { - return; - } - - this.publish({ - response_needed: true, - previous: this.previousState, - current: this.currentState - }).then(r => { - if (this.isDestroyed) { - return; - } - this.set("presenceUsers", r.users); - this.set("channel", r.messagebus_channel); - - if (!r.messagebus_channel) { - return; - } - - this.messageBus.subscribe( - r.messagebus_channel, - message => { - if (!this.isDestroyed) this.set("presenceUsers", message.users); - this._clearTimer = debounce( - this, - "clear", - keepAliveDuration + bufferTime - ); - }, - r.messagebus_id - ); - }); - }, - - clear() { - if (!this.isDestroyed) this.set("presenceUsers", []); - }, - - publish(data) { - this._lastPublish = new Date(); - - // Don't publish presence if disabled - if (this.currentUser.hide_profile_and_presence) { - return Promise.resolve(); - } - - return ajax("/presence/publish", { type: "POST", data }); - }, - - @computed("presenceUsers", "currentUser.id") - users(users, currentUserId) { - return (users || []).filter(user => user.id !== currentUserId); + _cancelThrottle() { + cancel(this._throttle); } }); diff --git a/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 index 1089246fb6..9cfb46f7ba 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 @@ -1,59 +1,21 @@ -import { cancel, debounce } from "@ember/runloop"; import Component from "@ember/component"; -import { gt } from "@ember/object/computed"; -import computed, { on } from "discourse-common/utils/decorators"; -import { - keepAliveDuration, - bufferTime -} from "discourse/plugins/discourse-presence/discourse/components/composer-presence-display"; - -const MB_GET_LAST_MESSAGE = -2; +import { gt, readOnly } from "@ember/object/computed"; +import { on } from "discourse-common/utils/decorators"; export default Component.extend({ - topicId: null, - presenceUsers: null, + topic: null, + presenceManager: readOnly("topic.presenceManager"), + users: readOnly("presenceManager.users"), shouldDisplay: gt("users.length", 0), - clear() { - if (!this.isDestroyed) this.set("presenceUsers", []); - }, - @on("didInsertElement") - _inserted() { - this.clear(); - - this.messageBus.subscribe( - this.channel, - message => { - if (!this.isDestroyed) this.set("presenceUsers", message.users); - this._clearTimer = debounce( - this, - "clear", - keepAliveDuration + bufferTime - ); - }, - MB_GET_LAST_MESSAGE - ); + subscribe() { + this.get("presenceManager").subscribe(); }, @on("willDestroyElement") _destroyed() { - cancel(this._clearTimer); - this.messageBus.unsubscribe(this.channel); - }, - - @computed("topicId") - channel(topicId) { - return `/presence/topic/${topicId}`; - }, - - @computed("presenceUsers", "currentUser.{id,ignored_users}") - users(users, currentUser) { - const ignoredUsers = currentUser.ignored_users || []; - return (users || []).filter( - user => - user.id !== currentUser.id && !ignoredUsers.includes(user.username) - ); + this.get("presenceManager").unsubscribe(); } }); diff --git a/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 new file mode 100644 index 0000000000..fe5c1bd6b6 --- /dev/null +++ b/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 @@ -0,0 +1,201 @@ +import EmberObject from "@ember/object"; +import { cancel, later, throttle } from "@ember/runloop"; +import { ajax } from "discourse/lib/ajax"; +import discourseComputed from "discourse-common/utils/decorators"; + +// The durations chosen here determines the accuracy of the presence feature and +// is tied closely with the server side implementation. Decreasing the duration +// to increase the accuracy will come at the expense of having to more network +// calls to publish the client's state. +// +// Logic walk through of our heuristic implementation: +// - When client A is typing, a message is published every KEEP_ALIVE_DURATION_SECONDS. +// - Client B receives the message and stores each user in an array and marks +// the user with a client-side timestamp of when the user was seen. +// - If client A continues to type, client B will continue to receive messages to +// update the client-side timestamp of when client A was last seen. +// - If client A disconnects or becomes inactive, the state of client A will be +// cleaned up on client B by a scheduler that runs every TIMER_INTERVAL_MILLISECONDS +const KEEP_ALIVE_DURATION_SECONDS = 10; +const BUFFER_DURATION_SECONDS = KEEP_ALIVE_DURATION_SECONDS + 2; + +const MESSAGE_BUS_LAST_ID = 0; +const TIMER_INTERVAL_MILLISECONDS = 2000; + +export const REPLYING = "replying"; +export const EDITING = "editing"; +export const CLOSED = "closed"; + +const PresenceManager = EmberObject.extend({ + users: null, + editingUsers: null, + subscribed: null, + topic: null, + currentUser: null, + messageBus: null, + siteSettings: null, + + init() { + this._super(...arguments); + + this.setProperties({ + users: [], + editingUsers: [], + subscribed: false + }); + }, + + subscribe() { + if (this.subscribed) return; + + this.messageBus.subscribe( + this.channel, + message => { + const { user, state } = message; + if (this.get("currentUser.id") === user.id) return; + + switch (state) { + case REPLYING: + this._appendUser(this.users, user); + break; + case EDITING: + this._appendUser(this.editingUsers, user, { + post_id: parseInt(message.post_id, 10) + }); + break; + case CLOSED: + this._removeUser(user); + break; + } + }, + MESSAGE_BUS_LAST_ID + ); + + this.set("subscribed", true); + }, + + unsubscribe() { + this.messageBus.unsubscribe(this.channel); + this._stopTimer(); + this.set("subscribed", false); + }, + + @discourseComputed("topic.id") + channel(topicId) { + return `/presence/${topicId}`; + }, + + throttlePublish(state, whisper, postId) { + return throttle( + this, + this.publish, + state, + whisper, + postId, + KEEP_ALIVE_DURATION_SECONDS * 1000 + ); + }, + + publish(state, whisper, postId) { + const data = { + state, + topic_id: this.get("topic.id") + }; + + if (whisper) { + data.is_whisper = 1; + } + + if (postId) { + data.post_id = postId; + } + + return ajax("/presence/publish", { + type: "POST", + data + }); + }, + + _removeUser(user) { + [this.users, this.editingUsers].forEach(users => { + const existingUser = users.findBy("id", user.id); + if (existingUser) users.removeObject(existingUser); + }); + }, + + _cleanUpUsers() { + [this.users, this.editingUsers].forEach(users => { + const staleUsers = []; + + users.forEach(user => { + if (user.last_seen <= Date.now() - BUFFER_DURATION_SECONDS * 1000) { + staleUsers.push(user); + } + }); + + users.removeObjects(staleUsers); + }); + + return this.users.length === 0 && this.editingUsers.length === 0; + }, + + _appendUser(users, user, attrs) { + let existingUser; + let usersLength = 0; + + users.forEach(u => { + if (u.id === user.id) { + existingUser = u; + } + + if (attrs && attrs.post_id) { + if (u.post_id === attrs.post_id) usersLength++; + } else { + usersLength++; + } + }); + + const props = attrs || {}; + props.last_seen = Date.now(); + + if (existingUser) { + existingUser.setProperties(props); + } else { + const limit = this.get("siteSettings.presence_max_users_shown"); + + if (usersLength < limit) { + users.pushObject(EmberObject.create(Object.assign(user, props))); + } + } + + this._startTimer(() => { + this._cleanUpUsers(); + }); + }, + + _scheduleTimer(callback) { + return later( + this, + () => { + const stop = callback(); + + if (!stop) { + this.set("_timer", this._scheduleTimer(callback)); + } + }, + TIMER_INTERVAL_MILLISECONDS + ); + }, + + _stopTimer() { + cancel(this._timer); + }, + + _startTimer(callback) { + if (!this._timer) { + this.set("_timer", this._scheduleTimer(callback)); + } + } +}); + +export default PresenceManager; diff --git a/plugins/discourse-presence/assets/javascripts/discourse/templates/components/composer-presence-display.hbs b/plugins/discourse-presence/assets/javascripts/discourse/templates/components/composer-presence-display.hbs index 97936135d0..453b13d07a 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/templates/components/composer-presence-display.hbs +++ b/plugins/discourse-presence/assets/javascripts/discourse/templates/components/composer-presence-display.hbs @@ -1,7 +1,7 @@ {{#if shouldDisplay}}
    - {{#each users as |user|}} + {{#each presenceUsers as |user|}} {{avatar user avatarTemplatePath="avatar_template" usernamePath="username" imageSize="small"}} {{/each}}
    @@ -16,4 +16,4 @@ --}}...
    -{{/if}} \ No newline at end of file +{{/if}} diff --git a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.hbs b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.hbs index af4de7c592..8fa1fb3862 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.hbs +++ b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.hbs @@ -4,4 +4,5 @@ topic=model.topic reply=model.reply title=model.title + whisper=model.whisper }} diff --git a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.hbs b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.hbs index 0ee449cf1d..c8514c7edc 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.hbs +++ b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.hbs @@ -1 +1 @@ -{{topic-presence-display topicId=model.id}} +{{topic-presence-display topic=model}} diff --git a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 new file mode 100644 index 0000000000..1b591ce4d1 --- /dev/null +++ b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 @@ -0,0 +1,42 @@ +import { withPluginApi } from "discourse/lib/plugin-api"; +import PresenceManager from "../discourse/lib/presence-manager"; + +function initializeDiscoursePresence(api) { + const currentUser = api.getCurrentUser(); + const siteSettings = api.container.lookup("site-settings:main"); + + if (currentUser && !currentUser.hide_profile_and_presence) { + api.modifyClass("model:topic", { + presenceManager: null + }); + + api.modifyClass("route:topic-from-params", { + setupController() { + this._super(...arguments); + + this.modelFor("topic").set( + "presenceManager", + PresenceManager.create({ + topic: this.modelFor("topic"), + currentUser, + messageBus: api.container.lookup("message-bus:main"), + siteSettings + }) + ); + } + }); + } +} + +export default { + name: "discourse-presence", + after: "message-bus", + + initialize(container) { + const siteSettings = container.lookup("site-settings:main"); + + if (siteSettings.presence_enabled) { + withPluginApi("0.8.40", initializeDiscoursePresence); + } + } +}; diff --git a/plugins/discourse-presence/config/settings.yml b/plugins/discourse-presence/config/settings.yml index 07c96c3d2b..21fbddf5ff 100644 --- a/plugins/discourse-presence/config/settings.yml +++ b/plugins/discourse-presence/config/settings.yml @@ -4,5 +4,6 @@ plugins: client: true presence_max_users_shown: default: 5 + client: true min: 1 max: 50 diff --git a/plugins/discourse-presence/plugin.rb b/plugins/discourse-presence/plugin.rb index 54d694b069..ce91b1ad2e 100644 --- a/plugins/discourse-presence/plugin.rb +++ b/plugins/discourse-presence/plugin.rb @@ -2,8 +2,8 @@ # name: discourse-presence # about: Show which users are writing a reply to a topic -# version: 1.0 -# authors: André Pereira, David Taylor +# version: 2.0 +# authors: André Pereira, David Taylor, tgxworld # url: https://github.com/discourse/discourse/tree/master/plugins/discourse-presence enabled_site_setting :presence_enabled @@ -15,161 +15,155 @@ PLUGIN_NAME ||= -"discourse-presence" after_initialize do + MessageBus.register_client_message_filter('/presence/') do |message| + published_at = message.data["published_at"] + + if published_at + (Time.zone.now.to_i - published_at) <= ::Presence::MAX_BACKLOG_AGE_SECONDS + else + false + end + end + module ::Presence + MAX_BACKLOG_AGE_SECONDS = 10 + class Engine < ::Rails::Engine engine_name PLUGIN_NAME isolate_namespace Presence end end - module ::Presence::PresenceManager - MAX_BACKLOG_AGE ||= 60 - - def self.get_redis_key(type, id) - "presence:#{type}:#{id}" - end - - def self.get_messagebus_channel(type, id) - "/presence/#{type}/#{id}" - end - - # return true if a key was added - def self.add(type, id, user_id) - key = get_redis_key(type, id) - result = Discourse.redis.hset(key, user_id, Time.zone.now) - Discourse.redis.expire(key, MAX_BACKLOG_AGE) - result - end - - # return true if a key was deleted - def self.remove(type, id, user_id) - key = get_redis_key(type, id) - Discourse.redis.expire(key, MAX_BACKLOG_AGE) - Discourse.redis.hdel(key, user_id) > 0 - end - - def self.get_users(type, id) - user_ids = Discourse.redis.hkeys(get_redis_key(type, id)).map(&:to_i) - User.where(id: user_ids) - end - - def self.publish(type, id) - users = get_users(type, id) - serialized_users = users.map { |u| BasicUserSerializer.new(u, root: false) } - message = { users: serialized_users, time: Time.now.to_i } - messagebus_channel = get_messagebus_channel(type, id) - - topic = type == 'post' ? Post.find_by(id: id).topic : Topic.find_by(id: id) - - if topic.private_message? - user_ids = User.where('admin OR moderator').pluck(:id) + topic.allowed_users.pluck(:id) - group_ids = topic.allowed_groups.pluck(:id) - - MessageBus.publish( - messagebus_channel, - message.as_json, - user_ids: user_ids, - group_ids: group_ids, - max_backlog_age: MAX_BACKLOG_AGE - ) - else - MessageBus.publish( - messagebus_channel, - message.as_json, - group_ids: topic.secure_group_ids, - max_backlog_age: MAX_BACKLOG_AGE - ) - end - - users - end - - def self.cleanup(type, id) - has_changed = false - - # Delete entries older than 20 seconds - hash = Discourse.redis.hgetall(get_redis_key(type, id)) - hash.each do |user_id, time| - if Time.zone.now - Time.parse(time) >= 20 - has_changed |= remove(type, id, user_id) - end - end - - has_changed - end - - end - require_dependency "application_controller" class Presence::PresencesController < ::ApplicationController requires_plugin PLUGIN_NAME before_action :ensure_logged_in + before_action :ensure_presence_enabled - ACTIONS ||= [-"edit", -"reply"].freeze + EDITING_STATE = 'editing' + REPLYING_STATE = 'replying' + CLOSED_STATE = 'closed' - def publish - raise Discourse::NotFound if current_user.blank? || current_user.user_option.hide_profile_and_presence? - - data = params.permit( - :response_needed, - current: [:action, :topic_id, :post_id], - previous: [:action, :topic_id, :post_id] - ) - - payload = {} - - if data[:previous] && data[:previous][:action].in?(ACTIONS) - type = data[:previous][:post_id] ? 'post' : 'topic' - id = data[:previous][:post_id] ? data[:previous][:post_id] : data[:previous][:topic_id] - - topic = type == 'post' ? Post.find_by(id: id)&.topic : Topic.find_by(id: id) - - if topic - guardian.ensure_can_see!(topic) - - Presence::PresenceManager.remove(type, id, current_user.id) - Presence::PresenceManager.cleanup(type, id) - Presence::PresenceManager.publish(type, id) - end + def handle_message + [:state, :topic_id].each do |key| + raise ActionController::ParameterMissing.new(key) unless params.key?(key) end - if data[:current] && data[:current][:action].in?(ACTIONS) - type = data[:current][:post_id] ? 'post' : 'topic' - id = data[:current][:post_id] ? data[:current][:post_id] : data[:current][:topic_id] + topic_id = permitted_params[:topic_id] + topic = Topic.find_by(id: topic_id) - topic = type == 'post' ? Post.find_by(id: id)&.topic : Topic.find_by(id: id) + raise Discourse::InvalidParameters.new(:topic_id) unless topic + guardian.ensure_can_see!(topic) - if topic - guardian.ensure_can_see!(topic) + post = nil - Presence::PresenceManager.add(type, id, current_user.id) - Presence::PresenceManager.cleanup(type, id) - users = Presence::PresenceManager.publish(type, id) + if (permitted_params[:post_id]) + if (permitted_params[:state] != EDITING_STATE) + raise Discourse::InvalidParameters.new(:state) + end - if data[:response_needed] - messagebus_channel = Presence::PresenceManager.get_messagebus_channel(type, id) - users ||= Presence::PresenceManager.get_users(type, id) - payload = json_payload(messagebus_channel, users) + post = Post.find_by(id: permitted_params[:post_id]) + raise Discourse::InvalidParameters.new(:topic_id) unless post + + guardian.ensure_can_edit!(post) + end + + opts = { + max_backlog_age: Presence::MAX_BACKLOG_AGE_SECONDS + } + + case permitted_params[:state] + when EDITING_STATE + opts[:group_ids] = [Group::AUTO_GROUPS[:staff]] + + if !post.locked? && !permitted_params[:is_whisper] + opts[:user_ids] = [post.user_id] + + if topic.private_message? + if post.wiki + opts[:user_ids] = opts[:user_ids].concat( + topic.allowed_users.where( + "trust_level >= ? AND NOT admin OR moderator", + SiteSetting.min_trust_to_edit_wiki_post + ).pluck(:id) + ) + + opts[:user_ids].uniq! + + # Ignore trust level and just publish to all allowed groups since + # trying to figure out which users in the allowed groups have + # the necessary trust levels can lead to a large array of user ids + # if the groups are big. + opts[:group_ids] = opts[:group_ids].concat( + topic.allowed_groups.pluck(:id) + ) + end + else + if post.wiki + opts[:group_ids] << Group::AUTO_GROUPS[:"trust_level_#{SiteSetting.min_trust_to_edit_wiki_post}"] + elsif SiteSetting.trusted_users_can_edit_others? + opts[:group_ids] << Group::AUTO_GROUPS[:trust_level_4] + end end end + when REPLYING_STATE + if permitted_params[:is_whisper] + opts[:group_ids] = [Group::AUTO_GROUPS[:staff]] + elsif topic.private_message? + opts[:user_ids] = topic.allowed_users.pluck(:id) + + opts[:group_ids] = [Group::AUTO_GROUPS[:staff]].concat( + topic.allowed_groups.pluck(:id) + ) + else + opts[:group_ids] = topic.secure_group_ids + end + when CLOSED_STATE + if topic.private_message? + opts[:user_ids] = topic.allowed_users.pluck(:id) + + opts[:group_ids] = [Group::AUTO_GROUPS[:staff]].concat( + topic.allowed_groups.pluck(:id) + ) + else + opts[:group_ids] = topic.secure_group_ids + end end - render json: payload - end - - def json_payload(channel, users) - { - messagebus_channel: channel, - messagebus_id: MessageBus.last_id(channel), - users: users.limit(SiteSetting.presence_max_users_shown).map { |u| BasicUserSerializer.new(u, root: false) } + payload = { + user: BasicUserSerializer.new(current_user, root: false).as_json, + state: permitted_params[:state], + is_whisper: permitted_params[:is_whisper].present?, + published_at: Time.zone.now.to_i } + + if (post_id = permitted_params[:post_id]).present? + payload[:post_id] = post_id + end + + MessageBus.publish("/presence/#{topic_id}", payload, opts) + + render json: success_json end + private + + def ensure_presence_enabled + if !SiteSetting.presence_enabled || + current_user.user_option.hide_profile_and_presence? + + raise Discourse::NotFound + end + end + + def permitted_params + params.permit(:state, :topic_id, :post_id, :is_whisper) + end end Presence::Engine.routes.draw do - post '/publish' => 'presences#publish' + post '/publish' => 'presences#handle_message' end Discourse::Application.routes.append do diff --git a/plugins/discourse-presence/spec/presence_manager_spec.rb b/plugins/discourse-presence/spec/presence_manager_spec.rb deleted file mode 100644 index b6cf1155ce..0000000000 --- a/plugins/discourse-presence/spec/presence_manager_spec.rb +++ /dev/null @@ -1,108 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe ::Presence::PresenceManager do - - let(:user1) { Fabricate(:user) } - let(:user2) { Fabricate(:user) } - let(:user3) { Fabricate(:user) } - let(:manager) { ::Presence::PresenceManager } - - let(:post1) { Fabricate(:post) } - let(:post2) { Fabricate(:post) } - - after(:each) do - Discourse.redis.del("presence:topic:#{post1.topic.id}") - Discourse.redis.del("presence:topic:#{post2.topic.id}") - Discourse.redis.del("presence:post:#{post1.id}") - Discourse.redis.del("presence:post:#{post2.id}") - end - - it 'adds, removes and lists users correctly' do - expect(manager.get_users('post', post1.id).count).to eq(0) - - expect(manager.add('post', post1.id, user1.id)).to be true - expect(manager.add('post', post1.id, user2.id)).to be true - expect(manager.add('post', post2.id, user3.id)).to be true - - expect(manager.get_users('post', post1.id).count).to eq(2) - expect(manager.get_users('post', post2.id).count).to eq(1) - - expect(manager.get_users('post', post1.id)).to contain_exactly(user1, user2) - expect(manager.get_users('post', post2.id)).to contain_exactly(user3) - - expect(manager.remove('post', post1.id, user1.id)).to be true - expect(manager.get_users('post', post1.id).count).to eq(1) - expect(manager.get_users('post', post1.id)).to contain_exactly(user2) - end - - it 'publishes correctly' do - expect(manager.get_users('post', post1.id).count).to eq(0) - - manager.add('post', post1.id, user1.id) - manager.add('post', post1.id, user2.id) - - messages = MessageBus.track_publish do - manager.publish('post', post1.id) - end - - expect(messages.count).to eq (1) - message = messages.first - - expect(message.channel).to eq("/presence/post/#{post1.id}") - - expect(message.data["users"].map { |u| u[:id] }).to contain_exactly(user1.id, user2.id) - end - - it 'publishes private message securely' do - private_post = Fabricate(:private_message_post) - manager.add('post', private_post.id, user2.id) - - messages = MessageBus.track_publish do - manager.publish('post', private_post.id) - end - - expect(messages.count).to eq (1) - message = messages.first - - expect(message.channel).to eq("/presence/post/#{private_post.id}") - - user_ids = User.where('admin or moderator').pluck(:id) - user_ids += private_post.topic.allowed_users.pluck(:id) - expect(message.user_ids).to contain_exactly(*user_ids) - end - - it 'publishes private category securely' do - group = Fabricate(:group) - category = Fabricate(:private_category, group: group) - private_topic = Fabricate(:topic, category: category) - - manager.add('topic', private_topic.id, user2.id) - - messages = MessageBus.track_publish do - manager.publish('topic', private_topic.id) - end - - expect(messages.count).to eq (1) - message = messages.first - - expect(message.channel).to eq("/presence/topic/#{private_topic.id}") - - expect(message.group_ids).to contain_exactly(*private_topic.secure_group_ids) - end - - it 'cleans up correctly' do - freeze_time Time.zone.now do - expect(manager.add('post', post1.id, user1.id)).to be true - expect(manager.cleanup('post', post1.id)).to be false # Nothing to cleanup - expect(manager.get_users('post', post1.id).count).to eq(1) - end - - # Anything older than 20 seconds should be cleaned up - freeze_time 30.seconds.from_now do - expect(manager.cleanup('post', post1.id)).to be true - expect(manager.get_users('post', post1.id).count).to eq(0) - end - end -end diff --git a/plugins/discourse-presence/spec/requests/presence_controller_spec.rb b/plugins/discourse-presence/spec/requests/presence_controller_spec.rb index 80547019a7..c13e04fa6c 100644 --- a/plugins/discourse-presence/spec/requests/presence_controller_spec.rb +++ b/plugins/discourse-presence/spec/requests/presence_controller_spec.rb @@ -3,170 +3,442 @@ require 'rails_helper' describe ::Presence::PresencesController do - before do - SiteSetting.presence_enabled = true - end + describe '#handle_message' do + context 'when not logged in' do + it 'should raise the right error' do + post '/presence/publish.json' - let(:user1) { Fabricate(:user) } - let(:user2) { Fabricate(:user) } - let(:user3) { Fabricate(:user) } + expect(response.status).to eq(403) + end + end - let(:post1) { Fabricate(:post) } - let(:post2) { Fabricate(:post) } + context 'when logged in' do + fab!(:user) { Fabricate(:user) } + fab!(:user2) { Fabricate(:user) } + fab!(:admin) { Fabricate(:admin) } - let(:manager) { ::Presence::PresenceManager } + fab!(:group) do + group = Fabricate(:group) + group.add(user) + group + end - after do - Discourse.redis.del("presence:topic:#{post1.topic.id}") - Discourse.redis.del("presence:topic:#{post2.topic.id}") - Discourse.redis.del("presence:post:#{post1.id}") - Discourse.redis.del("presence:post:#{post2.id}") - end + fab!(:category) { Fabricate(:private_category, group: group) } + fab!(:private_topic) { Fabricate(:topic, category: category) } + fab!(:public_topic) { Fabricate(:topic, first_post: Fabricate(:post)) } - context 'when not logged in' do - it 'should raise the right error' do - post '/presence/publish.json' - expect(response.status).to eq(403) + fab!(:private_message) do + Fabricate(:private_message_topic, + allowed_groups: [group] + ) + end + + before do + sign_in(user) + end + + it 'returns the right response when user disables the presence feature' do + user.user_option.update_column(:hide_profile_and_presence, true) + + post '/presence/publish.json' + + expect(response.status).to eq(404) + end + + it 'returns the right response when the presence site settings is disabled' do + SiteSetting.presence_enabled = false + + post '/presence/publish.json' + + expect(response.status).to eq(404) + end + + it 'returns the right response if required params are missing' do + post '/presence/publish.json' + + expect(response.status).to eq(400) + end + + it 'returns the right response if topic_id is invalid' do + post '/presence/publish.json', params: { topic_id: -999, state: 'replying' } + + expect(response.status).to eq(400) + end + + it 'returns the right response when user does not have access to the topic' do + group.remove(user) + + post '/presence/publish.json', params: { topic_id: private_topic.id, state: 'replying' } + + expect(response.status).to eq(403) + end + + it 'returns the right response when an invalid state is provided with a post_id' do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: public_topic.first_post.id, + state: 'some state' + } + + expect(response.status).to eq(400) + end + + it 'returns the right response when user can not edit a post' do + Fabricate(:post, topic: private_topic, user: private_topic.user) + + post '/presence/publish.json', params: { + topic_id: private_topic.id, + post_id: private_topic.first_post.id, + state: 'editing' + } + + expect(response.status).to eq(403) + end + + it 'returns the right response when an invalid post_id is given' do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: -9, + state: 'editing' + } + + expect(response.status).to eq(400) + end + + it 'publishes the right message for a public topic' do + freeze_time + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { topic_id: public_topic.id, state: 'replying' } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.channel).to eq("/presence/#{public_topic.id}") + expect(message.data.dig(:user, :id)).to eq(user.id) + expect(message.data[:published_at]).to eq(Time.zone.now.to_i) + expect(message.group_ids).to eq(nil) + expect(message.user_ids).to eq(nil) + end + + it 'publishes the right message for a restricted topic' do + freeze_time + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: private_topic.id, + state: 'replying' + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.channel).to eq("/presence/#{private_topic.id}") + expect(message.data.dig(:user, :id)).to eq(user.id) + expect(message.data[:published_at]).to eq(Time.zone.now.to_i) + expect(message.group_ids).to contain_exactly(group.id) + expect(message.user_ids).to eq(nil) + end + + it 'publishes the right message for a private message' do + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: private_message.id, + state: 'replying' + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly( + group.id, + Group::AUTO_GROUPS[:staff] + ) + + expect(message.user_ids).to contain_exactly( + *private_message.topic_allowed_users.pluck(:user_id) + ) + end + + it 'publishes the message to staff group when user is whispering' do + SiteSetting.enable_whispers = true + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + state: 'replying', + is_whisper: true + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly(Group::AUTO_GROUPS[:staff]) + expect(message.user_ids).to eq(nil) + end + + it 'publishes the message to staff group when a staff is editing a whisper' do + SiteSetting.enable_whispers = true + sign_in(admin) + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: public_topic.first_post.id, + state: 'editing', + is_whisper: true + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly(Group::AUTO_GROUPS[:staff]) + expect(message.user_ids).to eq(nil) + end + + it 'publishes the message to staff group when a staff is editing a locked post' do + SiteSetting.enable_whispers = true + sign_in(admin) + locked_post = Fabricate(:post, topic: public_topic, locked_by_id: admin.id) + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: locked_post.id, + state: 'editing', + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly(Group::AUTO_GROUPS[:staff]) + expect(message.user_ids).to eq(nil) + end + + it 'publishes the message to author, staff group and TL4 group when editing a public post' do + post = Fabricate(:post, topic: public_topic, user: user) + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: post.id, + state: 'editing', + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly( + Group::AUTO_GROUPS[:trust_level_4], + Group::AUTO_GROUPS[:staff] + ) + + expect(message.user_ids).to contain_exactly(user.id) + end + + it 'publishes the message to author and staff group when editing a public post ' \ + 'if SiteSettings.trusted_users_can_edit_others is set to false' do + + post = Fabricate(:post, topic: public_topic, user: user) + SiteSetting.trusted_users_can_edit_others = false + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: post.id, + state: 'editing', + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly(Group::AUTO_GROUPS[:staff]) + expect(message.user_ids).to contain_exactly(user.id) + end + + it 'publishes the message to SiteSetting.min_trust_to_edit_wiki_post group ' \ + 'and staff group when editing a wiki in a public topic' do + + post = Fabricate(:post, topic: public_topic, user: user, wiki: true) + SiteSetting.min_trust_to_edit_wiki_post = TrustLevel.levels[:basic] + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + post_id: post.id, + state: 'editing', + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly( + Group::AUTO_GROUPS[:trust_level_1], + Group::AUTO_GROUPS[:staff] + ) + + expect(message.user_ids).to contain_exactly(user.id) + end + + it 'publishes the message to author and staff group when editing a private message' do + post = Fabricate(:post, topic: private_message, user: user) + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: private_message.id, + post_id: post.id, + state: 'editing', + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly( + Group::AUTO_GROUPS[:staff], + ) + + expect(message.user_ids).to contain_exactly(user.id) + end + + it 'publishes the message to users with trust levels of SiteSetting.min_trust_to_edit_wiki_post ' \ + 'and staff group when editing a wiki in a private message' do + + post = Fabricate(:post, + topic: private_message, + user: private_message.user, + wiki: true + ) + + user2.update!(trust_level: TrustLevel.levels[:newuser]) + group.add(user2) + + SiteSetting.min_trust_to_edit_wiki_post = TrustLevel.levels[:basic] + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: private_message.id, + post_id: post.id, + state: 'editing', + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly( + Group::AUTO_GROUPS[:staff], + group.id + ) + + expect(message.user_ids).to contain_exactly( + *private_message.allowed_users.pluck(:id) + ) + end + + it 'publises the right message when closing composer in public topic' do + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: public_topic.id, + state: described_class::CLOSED_STATE, + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to eq(nil) + expect(message.user_ids).to eq(nil) + end + + it 'publises the right message when closing composer in private topic' do + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: private_topic.id, + state: described_class::CLOSED_STATE, + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly(group.id) + expect(message.user_ids).to eq(nil) + end + + it 'publises the right message when closing composer in private message' do + post = Fabricate(:post, topic: private_message, user: user) + + messages = MessageBus.track_publish do + post '/presence/publish.json', params: { + topic_id: private_message.id, + state: described_class::CLOSED_STATE, + } + + expect(response.status).to eq(200) + end + + expect(messages.length).to eq(1) + + message = messages.first + + expect(message.group_ids).to contain_exactly( + Group::AUTO_GROUPS[:staff], + group.id + ) + + expect(message.user_ids).to contain_exactly( + *private_message.allowed_users.pluck(:id) + ) + end end end - - context 'when logged in' do - before do - sign_in(user1) - end - - it "doesn't produce an error" do - expect { post '/presence/publish.json' }.not_to raise_error - end - - it "does not publish for users with disabled presence features" do - user1.user_option.update_column(:hide_profile_and_presence, true) - post '/presence/publish.json' - expect(response.code).to eq("404") - end - - it "uses guardian to secure endpoint" do - private_post = Fabricate(:private_message_post) - - post '/presence/publish.json', params: { - current: { action: 'edit', post_id: private_post.id } - } - - expect(response.code.to_i).to eq(403) - - group = Fabricate(:group) - category = Fabricate(:private_category, group: group) - private_topic = Fabricate(:topic, category: category) - - post '/presence/publish.json', params: { - current: { action: 'edit', topic_id: private_topic.id } - } - - expect(response.code.to_i).to eq(403) - end - - it "returns a response when requested" do - messages = MessageBus.track_publish do - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post1.id }, response_needed: true - } - end - - expect(messages.count).to eq(1) - - data = JSON.parse(response.body) - - expect(data['messagebus_channel']).to eq("/presence/post/#{post1.id}") - expect(data['messagebus_id']).to eq(MessageBus.last_id("/presence/post/#{post1.id}")) - expect(data['users'][0]["id"]).to eq(user1.id) - end - - it "doesn't return a response when not requested" do - messages = MessageBus.track_publish do - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - end - - expect(messages.count).to eq(1) - - data = JSON.parse(response.body) - expect(data).to eq({}) - end - - it "does send duplicate messagebus messages" do - messages = MessageBus.track_publish do - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - end - - expect(messages.count).to eq(1) - - messages = MessageBus.track_publish do - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - end - - # we do this cause we also publish time - expect(messages.count).to eq(1) - end - - it "clears 'previous' state when supplied" do - messages = MessageBus.track_publish do - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post2.id }, - previous: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - end - - expect(messages.count).to eq(3) - end - - it 'cleans up old users when requested' do - freeze_time Time.zone.now do - manager.add('topic', post1.topic.id, user2.id) - end - - # Anything older than 20 seconds should be cleaned up - freeze_time 30.seconds.from_now do - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'reply', topic_id: post1.topic.id }, response_needed: true - } - - data = JSON.parse(response.body) - - expect(data['users'].length).to eq(1) - end - - end - - describe 'when post has been deleted' do - it 'should return an empty response' do - post1.destroy! - - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - - expect(response.status).to eq(200) - expect(JSON.parse(response.body)).to eq({}) - - post '/presence/publish.json', params: { - current: { compose_state: 'open', action: 'edit', post_id: post2.id }, - previous: { compose_state: 'open', action: 'edit', post_id: post1.id } - } - - expect(response.status).to eq(200) - expect(JSON.parse(response.body)).to eq({}) - end - end - - end - end From 2045f51312bb278d37990f4daa88147090bc3793 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 29 Apr 2020 15:23:17 +1000 Subject: [PATCH 0842/1830] FIX: correctly account for direct replies with presence followup to 301a0fa5, we were not checking the action so we were publishing some messages from composers we did not intend to --- .../components/composer-presence-display.js.es6 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 index e6a366087b..72edf988f7 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 @@ -6,6 +6,7 @@ import discourseComputed, { on } from "discourse-common/utils/decorators"; import { REPLYING, CLOSED, EDITING } from "../lib/presence-manager"; +import { REPLY, EDIT } from "discourse/models/composer"; export default Component.extend({ // Passed in variables @@ -44,12 +45,18 @@ export default Component.extend({ @observes("reply", "title") typing() { if (this.presenceManager) { + let action = this.action; + + if (action !== REPLY && action !== EDIT) { + return; + } + const postId = this.get("post.id"); this._throttle = this.presenceManager.throttlePublish( - postId ? EDITING : REPLYING, + action === EDIT ? EDITING : REPLYING, this.whisper, - postId + action === EDIT ? postId : undefined ); } }, From 8b3b5d1474137a08a33a4d9827aa36fd62be2e87 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 13:39:02 +0800 Subject: [PATCH 0843/1830] DEV: Disable `discourse-presence` in Ember test env. --- .../discourse/components/topic-presence-display.js.es6 | 4 ++-- .../assets/javascripts/initializers/discourse-presence.js.es6 | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 index 9cfb46f7ba..1f8ec4d27a 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 @@ -11,11 +11,11 @@ export default Component.extend({ @on("didInsertElement") subscribe() { - this.get("presenceManager").subscribe(); + this.presenceManager && this.presenceManager.subscribe(); }, @on("willDestroyElement") _destroyed() { - this.get("presenceManager").unsubscribe(); + this.presenceManager && this.presenceManager.unsubscribe(); } }); diff --git a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 index 1b591ce4d1..f1558d0578 100644 --- a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 @@ -35,7 +35,7 @@ export default { initialize(container) { const siteSettings = container.lookup("site-settings:main"); - if (siteSettings.presence_enabled) { + if (siteSettings.presence_enabled && ENV.environment !== "test") { withPluginApi("0.8.40", initializeDiscoursePresence); } } From 197d0332e639f786560fdb6a535fdcd1eeb94a70 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 13:48:31 +0800 Subject: [PATCH 0844/1830] DEV: Missing import. --- .../assets/javascripts/initializers/discourse-presence.js.es6 | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 index f1558d0578..27a7252426 100644 --- a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 @@ -1,5 +1,6 @@ import { withPluginApi } from "discourse/lib/plugin-api"; import PresenceManager from "../discourse/lib/presence-manager"; +import ENV from "discourse-common/config/environment"; function initializeDiscoursePresence(api) { const currentUser = api.getCurrentUser(); From 960fd94758ef97ec5faf444068a5073bdff9772b Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 13:48:38 +0800 Subject: [PATCH 0845/1830] DEV: Run rubocop in parallel in pre-commit hook. --- lefthook.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lefthook.yml b/lefthook.yml index 749f080134..f3645c3d1a 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -3,7 +3,7 @@ pre-commit: commands: rubocop: glob: "*.rb" - run: bundle exec rubocop {staged_files} + run: bundle exec rubocop --parallel {staged_files} prettier: glob: "*.{js,es6}" exclude: "vendor/*|fixtures|public/javascripts|shims.js|ember-addons|template-lintrc|locale/*|test_helper|run-qunit" From 1d04fb24f8cbe078990332117fcffda4bd6ea3e5 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 14:07:42 +0800 Subject: [PATCH 0846/1830] DEV: Enable all the ActiveRecord goodness in development env. --- config/environments/development.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 2a612c7164..0adc84a086 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -39,7 +39,7 @@ Discourse::Application.configure do config.log_level = ENV['DISCOURSE_DEV_LOG_LEVEL'] if ENV['DISCOURSE_DEV_LOG_LEVEL'] - if ENV['RAILS_VERBOSE_QUERY_LOGS'] + if ENV['RAILS_VERBOSE_QUERY_LOGS'] != 0 config.active_record.verbose_query_logs = true end @@ -78,6 +78,10 @@ Discourse::Application.configure do end config.after_initialize do + if ENV["RAILS_COLORIZE_LOGGING"] != "0" + config.colorize_logging = true + end + if ENV['BULLET'] Bullet.enable = true Bullet.rails_logger = true From fa21c03a1dc70cb1a3ef2a65140d1520a0e05eaf Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 14:09:19 +0800 Subject: [PATCH 0847/1830] DEV: Minor follow up to 1d04fb24f8cbe078990332117fcffda4bd6ea3e5 --- config/environments/development.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 0adc84a086..360ae8ae8f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -39,7 +39,7 @@ Discourse::Application.configure do config.log_level = ENV['DISCOURSE_DEV_LOG_LEVEL'] if ENV['DISCOURSE_DEV_LOG_LEVEL'] - if ENV['RAILS_VERBOSE_QUERY_LOGS'] != 0 + if ENV['RAILS_VERBOSE_QUERY_LOGS'] != "0" config.active_record.verbose_query_logs = true end From a078feee07d1e55a4a6fc7e1058b8671922eaa8c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 14:19:14 +0800 Subject: [PATCH 0848/1830] DEV: Turn off ActiveRecord development color and query log by default. It breaks logster. --- config/environments/development.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 360ae8ae8f..56bc6aad8b 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -39,7 +39,7 @@ Discourse::Application.configure do config.log_level = ENV['DISCOURSE_DEV_LOG_LEVEL'] if ENV['DISCOURSE_DEV_LOG_LEVEL'] - if ENV['RAILS_VERBOSE_QUERY_LOGS'] != "0" + if ENV['RAILS_VERBOSE_QUERY_LOGS'] != "1" config.active_record.verbose_query_logs = true end @@ -78,7 +78,7 @@ Discourse::Application.configure do end config.after_initialize do - if ENV["RAILS_COLORIZE_LOGGING"] != "0" + if ENV["RAILS_COLORIZE_LOGGING"] != "1" config.colorize_logging = true end From 16ab6430feefb714325816a3123eb37a56c8df4a Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 14:24:48 +0800 Subject: [PATCH 0849/1830] DEV: Follow up to a078feee07d1e55a4a6fc7e1058b8671922eaa8c --- config/environments/development.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 56bc6aad8b..3643c5b769 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -25,6 +25,7 @@ Discourse::Application.configure do config.assets.digest = false config.assets.debug = false + config.assets.quiet = true # Raise an error on page load if there are pending migrations config.active_record.migration_error = :page_load @@ -39,7 +40,7 @@ Discourse::Application.configure do config.log_level = ENV['DISCOURSE_DEV_LOG_LEVEL'] if ENV['DISCOURSE_DEV_LOG_LEVEL'] - if ENV['RAILS_VERBOSE_QUERY_LOGS'] != "1" + if ENV['RAILS_VERBOSE_QUERY_LOGS'] == "1" config.active_record.verbose_query_logs = true end @@ -78,7 +79,7 @@ Discourse::Application.configure do end config.after_initialize do - if ENV["RAILS_COLORIZE_LOGGING"] != "1" + if ENV["RAILS_COLORIZE_LOGGING"] == "1" config.colorize_logging = true end From 4fe4b3cce37ebc8313d9dda78fe09bed3cbfd954 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 14:46:56 +0800 Subject: [PATCH 0850/1830] DEV: Revert quiet assets in dev. Breaks with a gem. --- config/environments/development.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 3643c5b769..e8d1d503e1 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -25,7 +25,6 @@ Discourse::Application.configure do config.assets.digest = false config.assets.debug = false - config.assets.quiet = true # Raise an error on page load if there are pending migrations config.active_record.migration_error = :page_load From ae54a337195db3afc4447e81e5231a3e2f41ac1a Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 29 Apr 2020 14:46:56 +0800 Subject: [PATCH 0851/1830] FIX: discourse-presence breaks composer for users. --- .../composer-presence-display.js.es6 | 34 ++++++++----------- .../components/topic-presence-display.js.es6 | 4 +-- .../discourse/lib/presence-manager.js.es6 | 2 ++ .../composer-fields/presence.js.es6 | 8 +++-- .../presence.js.es6 | 6 ++-- .../initializers/discourse-presence.js.es6 | 2 +- 6 files changed, 30 insertions(+), 26 deletions(-) diff --git a/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 index 72edf988f7..b1329b1ddd 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/components/composer-presence-display.js.es6 @@ -24,7 +24,7 @@ export default Component.extend({ @on("didInsertElement") subscribe() { - this.presenceManager && this.presenceManager.subscribe(); + this.presenceManager.subscribe(); }, @discourseComputed( @@ -44,21 +44,19 @@ export default Component.extend({ @observes("reply", "title") typing() { - if (this.presenceManager) { - let action = this.action; + let action = this.action; - if (action !== REPLY && action !== EDIT) { - return; - } - - const postId = this.get("post.id"); - - this._throttle = this.presenceManager.throttlePublish( - action === EDIT ? EDITING : REPLYING, - this.whisper, - action === EDIT ? postId : undefined - ); + if (action !== REPLY && action !== EDIT) { + return; } + + const postId = this.get("post.id"); + + this._throttle = this.presenceManager.throttlePublish( + action === EDIT ? EDITING : REPLYING, + this.whisper, + action === EDIT ? postId : undefined + ); }, @observes("whisper") @@ -68,17 +66,15 @@ export default Component.extend({ @observes("post.id") stopEditing() { - if (this.presenceManager && !this.get("post.id")) { + if (!this.get("post.id")) { this.presenceManager.publish(CLOSED, this.whisper); } }, @on("willDestroyElement") composerClosing() { - if (this.presenceManager) { - this._cancelThrottle(); - this.presenceManager.publish(CLOSED, this.whisper); - } + this._cancelThrottle(); + this.presenceManager.publish(CLOSED, this.whisper); }, _cancelThrottle() { diff --git a/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 index 1f8ec4d27a..bedb292144 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/components/topic-presence-display.js.es6 @@ -11,11 +11,11 @@ export default Component.extend({ @on("didInsertElement") subscribe() { - this.presenceManager && this.presenceManager.subscribe(); + this.presenceManager.subscribe(); }, @on("willDestroyElement") _destroyed() { - this.presenceManager && this.presenceManager.unsubscribe(); + this.presenceManager.unsubscribe(); } }); diff --git a/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 index fe5c1bd6b6..5943f76ce5 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/lib/presence-manager.js.es6 @@ -97,6 +97,8 @@ const PresenceManager = EmberObject.extend({ }, publish(state, whisper, postId) { + if (this.get("currentUser.hide_profile_and_presence")) return; + const data = { state, topic_id: this.get("topic.id") diff --git a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.js.es6 index 00fbc34d91..0240e68027 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/composer-fields/presence.js.es6 @@ -1,5 +1,9 @@ export default { - shouldRender(_, ctx) { - return ctx.siteSettings.presence_enabled; + shouldRender(args, component) { + return ( + component.siteSettings.presence_enabled && + args.model.topic && + args.model.topic.presenceManager + ); } }; diff --git a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.js.es6 b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.js.es6 index 00fbc34d91..db452d54c7 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/discourse/templates/connectors/topic-above-footer-buttons/presence.js.es6 @@ -1,5 +1,7 @@ export default { - shouldRender(_, ctx) { - return ctx.siteSettings.presence_enabled; + shouldRender(args, component) { + return ( + component.siteSettings.presence_enabled && args.model.presenceManager + ); } }; diff --git a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 index 27a7252426..98ec813198 100644 --- a/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 +++ b/plugins/discourse-presence/assets/javascripts/initializers/discourse-presence.js.es6 @@ -6,7 +6,7 @@ function initializeDiscoursePresence(api) { const currentUser = api.getCurrentUser(); const siteSettings = api.container.lookup("site-settings:main"); - if (currentUser && !currentUser.hide_profile_and_presence) { + if (currentUser) { api.modifyClass("model:topic", { presenceManager: null }); From 0a85a7aef9f5194b7e00b75bfe8b84c2376f0c65 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 29 Apr 2020 12:09:50 +0300 Subject: [PATCH 0852/1830] FEATURE: Add user_profile to user_archive CSV export (#9571) --- app/jobs/regular/export_csv_file.rb | 93 +++++++++++++++++++++-------- spec/jobs/export_csv_file_spec.rb | 7 +++ 2 files changed, 74 insertions(+), 26 deletions(-) diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb index 6092fb1a65..e8138d06c7 100644 --- a/app/jobs/regular/export_csv_file.rb +++ b/app/jobs/regular/export_csv_file.rb @@ -13,6 +13,7 @@ module Jobs HEADER_ATTRS_FOR ||= HashWithIndifferentAccess.new( user_archive: ['topic_title', 'categories', 'is_pm', 'post', 'like_count', 'reply_count', 'url', 'created_at'], + user_archive_profile: ['loncation', 'website', 'bio', 'views'], user_list: ['id', 'name', 'username', 'email', 'title', 'created_at', 'last_seen_at', 'last_posted_at', 'last_emailed_at', 'trust_level', 'approved', 'suspended_at', 'suspended_till', 'silenced_till', 'active', 'admin', 'moderator', 'ip_address', 'staged', 'secondary_emails'], user_stats: ['topics_entered', 'posts_read_count', 'time_read', 'topic_count', 'post_count', 'likes_given', 'likes_received'], user_profile: ['location', 'website', 'views'], @@ -29,49 +30,61 @@ module Jobs @extra = HashWithIndifferentAccess.new(args[:args]) if args[:args] @current_user = User.find_by(id: args[:user_id]) - export_method = :"#{@entity}_export" - raise Discourse::InvalidParameters.new(:entity) unless respond_to?(export_method) + entities = [{ name: @entity }] + entities << { name: "user_archive_profile" } if @entity === "user_archive" - file_name_prefix = if @entity == "user_archive" - "#{@entity.split('_').join('-')}-#{@current_user.username}-#{Time.now.strftime("%y%m%d-%H%M%S")}" - elsif @entity == "report" && @extra[:name].present? - "#{@extra[:name].split('_').join('-')}-#{Time.now.strftime("%y%m%d-%H%M%S")}" - else - "#{@entity.split('_').join('-')}-#{Time.now.strftime("%y%m%d-%H%M%S")}" + entities.each do |entity| + entity[:method] = :"#{entity[:name]}_export" + raise Discourse::InvalidParameters.new(:entity) unless respond_to?(entity[:method]) + + @timestamp ||= Time.now.strftime("%y%m%d-%H%M%S") + entity[:filename] = + if entity[:name] == "user_archive" || entity[:name] === "user_archive_profile" + "#{entity[:name].dasherize}-#{@current_user.username}-#{@timestamp}" + elsif entity[:name] == "report" && @extra[:name].present? + "#{@extra[:name].dasherize}-#{@timestamp}" + else + "#{entity[:name].dasherize}-#{@timestamp}" + end end export_title = if @entity == "report" && @extra[:name].present? I18n.t("reports.#{@extra[:name]}.title") else - @entity.split('_').join(' ').titleize + @entity.gsub('_', ' ').titleize end - user_export = UserExport.create(file_name: file_name_prefix, user_id: @current_user.id) - file_name = "#{file_name_prefix}-#{user_export.id}.csv" - absolute_path = "#{UserExport.base_directory}/#{file_name}" + filename = entities[0][:filename] # use first entity as a name for this export + user_export = UserExport.create(file_name: filename, user_id: @current_user.id) + + filename = "#{filename}-#{user_export.id}" + dirname = "#{UserExport.base_directory}/#{filename}" # ensure directory exists - FileUtils.mkdir_p(UserExport.base_directory) unless Dir.exists?(UserExport.base_directory) + FileUtils.mkdir_p(dirname) unless Dir.exists?(dirname) # Generate a compressed CSV file begin - CSV.open(absolute_path, "w") do |csv| - csv << get_header if @entity != "report" - public_send(export_method).each { |d| csv << d } + entities.each do |entity| + CSV.open("#{dirname}/#{entity[:filename]}.csv", "w") do |csv| + csv << get_header(entity[:name]) if entity[:name] != "report" + public_send(entity[:method]).each { |d| csv << d } + end end - compressed_file_path = Compression::Zip.new.compress(UserExport.base_directory, file_name) + + zip_filename = Compression::Zip.new.compress(UserExport.base_directory, filename) ensure - File.delete(absolute_path) + FileUtils.rm_rf(dirname) end # create upload upload = nil - if File.exist?(compressed_file_path) - File.open(compressed_file_path) do |file| + if File.exist?(zip_filename) + File.open(zip_filename) do |file| upload = UploadCreator.new( file, - File.basename(compressed_file_path), + File.basename(zip_filename), type: 'csv_export', for_export: 'true' ).create_for(@current_user.id) @@ -79,11 +92,11 @@ module Jobs if upload.persisted? user_export.update_columns(upload_id: upload.id) else - Rails.logger.warn("Failed to upload the file #{compressed_file_path}") + Rails.logger.warn("Failed to upload the file #{zip_filename}") end end - File.delete(compressed_file_path) + File.delete(zip_filename) end ensure post = notify_user(upload, export_title) @@ -108,6 +121,17 @@ module Jobs end end + def user_archive_profile_export + return enum_for(:user_archive_profile_export) unless block_given? + + UserProfile + .where(user_id: @current_user.id) + .select(:location, :website, :bio_raw, :views) + .each do |user_profile| + yield get_user_archive_profile_fields(user_profile) + end + end + def user_list_export return enum_for(:user_list_export) unless block_given? @@ -234,8 +258,8 @@ module Jobs data.each { |row| yield row.values_at(*header).map(&:to_s) } end - def get_header - if @entity == 'user_list' + def get_header(entity) + if entity == 'user_list' header_array = HEADER_ATTRS_FOR['user_list'] + HEADER_ATTRS_FOR['user_stats'] + HEADER_ATTRS_FOR['user_profile'] header_array.concat(HEADER_ATTRS_FOR['user_sso']) if SiteSetting.enable_sso user_custom_fields = UserField.all @@ -246,7 +270,7 @@ module Jobs end header_array.push("group_names") else - header_array = HEADER_ATTRS_FOR[@entity] + header_array = HEADER_ATTRS_FOR[entity] end header_array @@ -348,6 +372,23 @@ module Jobs user_archive_array end + def get_user_archive_profile_fields(user_profile) + user_archive_profile = [] + + HEADER_ATTRS_FOR['user_archive_profile'].each do |attr| + data = + if attr == 'bio' + user_profile.attributes['bio_raw'] + else + user_profile.attributes[attr] + end + + user_archive_profile.push(data) + end + + user_archive_profile + end + def get_staff_action_fields(staff_action) staff_action_array = [] diff --git a/spec/jobs/export_csv_file_spec.rb b/spec/jobs/export_csv_file_spec.rb index 8322265a72..9182f9f37d 100644 --- a/spec/jobs/export_csv_file_spec.rb +++ b/spec/jobs/export_csv_file_spec.rb @@ -36,6 +36,13 @@ describe Jobs::ExportCsvFile do expect(system_message.id).to eq(UserExport.last.topic_id) expect(system_message.closed).to eq(true) + + files = [] + Zip::File.open(Discourse.store.path_for(upload)) do |zip_file| + zip_file.each { |entry| files << entry.name } + end + + expect(files.size).to eq(2) ensure user.uploads.each(&:destroy!) end From 7a946b9f5cd1c86cc8cd1b4999c0c7fbee977036 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 29 Apr 2020 12:38:36 +0300 Subject: [PATCH 0853/1830] DEV: Fix typo Follow-up to 0a85a7aef9f5194b7e00b75bfe8b84c2376f0c65. --- app/jobs/regular/export_csv_file.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb index e8138d06c7..9485fc2fdc 100644 --- a/app/jobs/regular/export_csv_file.rb +++ b/app/jobs/regular/export_csv_file.rb @@ -13,7 +13,7 @@ module Jobs HEADER_ATTRS_FOR ||= HashWithIndifferentAccess.new( user_archive: ['topic_title', 'categories', 'is_pm', 'post', 'like_count', 'reply_count', 'url', 'created_at'], - user_archive_profile: ['loncation', 'website', 'bio', 'views'], + user_archive_profile: ['location', 'website', 'bio', 'views'], user_list: ['id', 'name', 'username', 'email', 'title', 'created_at', 'last_seen_at', 'last_posted_at', 'last_emailed_at', 'trust_level', 'approved', 'suspended_at', 'suspended_till', 'silenced_till', 'active', 'admin', 'moderator', 'ip_address', 'staged', 'secondary_emails'], user_stats: ['topics_entered', 'posts_read_count', 'time_read', 'topic_count', 'post_count', 'likes_given', 'likes_received'], user_profile: ['location', 'website', 'views'], From 4eed86919eae50216e6faafa18ae0bb626ffe92a Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 29 Apr 2020 13:30:34 +0200 Subject: [PATCH 0854/1830] FIX: ensures card cloak is removed (#9582) Repro steps for current failure: - use mobile view - click on a different user avatar to show user card - click message - close composer - cloak is still showing and prevents any click --- .../discourse/app/components/group-card-contents.js | 4 ++-- .../discourse/app/components/user-card-contents.js | 4 ++-- .../javascripts/discourse/app/mixins/card-contents-base.js | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/group-card-contents.js b/app/assets/javascripts/discourse/app/components/group-card-contents.js index 71884696fb..c4aafe5df4 100644 --- a/app/assets/javascripts/discourse/app/components/group-card-contents.js +++ b/app/assets/javascripts/discourse/app/components/group-card-contents.js @@ -65,9 +65,9 @@ export default Component.extend(CardContentsBase, CleansUp, { }, _close() { - this._super(...arguments); - this.set("group", null); + + this._super(...arguments); }, cleanUp() { diff --git a/app/assets/javascripts/discourse/app/components/user-card-contents.js b/app/assets/javascripts/discourse/app/components/user-card-contents.js index b4f0e5cf4b..629545601a 100644 --- a/app/assets/javascripts/discourse/app/components/user-card-contents.js +++ b/app/assets/javascripts/discourse/app/components/user-card-contents.js @@ -177,12 +177,12 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, { }, _close() { - this._super(...arguments); - this.setProperties({ user: null, topicPostCount: null }); + + this._super(...arguments); }, cleanUp() { diff --git a/app/assets/javascripts/discourse/app/mixins/card-contents-base.js b/app/assets/javascripts/discourse/app/mixins/card-contents-base.js index 2f53c5276f..b1aeb853dd 100644 --- a/app/assets/javascripts/discourse/app/mixins/card-contents-base.js +++ b/app/assets/javascripts/discourse/app/mixins/card-contents-base.js @@ -280,6 +280,8 @@ export default Mixin.create({ if (this.site.mobileView) { this._unbindMobileScroll(); } + + this._hide(); }, willDestroyElement() { From 6a9a7b56df2aa708624838d11fc602a4c13d5012 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Wed, 29 Apr 2020 12:55:30 +0100 Subject: [PATCH 0855/1830] DEV: Bump Hashie and Faraday (#9583) These were previously pinned due to a dependency in the zendesk plugin. That has now been resolved. --- Gemfile | 7 ------- Gemfile.lock | 6 ++---- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/Gemfile b/Gemfile index 925f81b86a..2b1fb36f22 100644 --- a/Gemfile +++ b/Gemfile @@ -257,10 +257,3 @@ end gem 'webpush', require: false gem 'colored2', require: false gem 'maxminddb' - -# These are not direct dependencies, but we need to restrict -# versions for compatibility with https://github.com/discourse/discourse-zendesk-plugin -# These restrictions can be removed once the zendesk_api gem is updated -# for newer versions of hashie and faraday -gem 'hashie', '< 4.0.0', require: false # https://github.com/zendesk/zendesk_api_client_rb/pull/422 -gem 'faraday', '< 1.0.0', require: false # https://github.com/zendesk/zendesk_api_client_rb/pull/421 diff --git a/Gemfile.lock b/Gemfile.lock index 7cb6c2ef68..5fc2845215 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -126,7 +126,7 @@ GEM exifr (1.3.6) fabrication (2.21.1) fakeweb (1.3.0) - faraday (0.17.3) + faraday (1.0.1) multipart-post (>= 1.2, < 3) fast_blank (1.0.0) fast_xor (1.1.3) @@ -142,7 +142,7 @@ GEM activesupport (>= 4.2.0) guess_html_encoding (0.0.11) hashdiff (1.0.1) - hashie (3.6.0) + hashie (4.1.0) highline (1.7.10) hkdf (0.3.0) htmlentities (4.3.4) @@ -463,14 +463,12 @@ DEPENDENCIES execjs fabrication fakeweb - faraday (< 1.0.0) fast_blank fast_xor fast_xs fastimage flamegraph gc_tracer - hashie (< 4.0.0) highline (~> 1.7.0) htmlentities http_accept_language From 7ccfc73edb2d61bf39649db70fdc16679d8fc056 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2020 12:58:52 +0100 Subject: [PATCH 0856/1830] Build(deps): Bump rqrcode_core from 0.1.1 to 0.1.2 (#9244) Bumps [rqrcode_core](https://github.com/whomwah/rqrcode_core) from 0.1.1 to 0.1.2. - [Release notes](https://github.com/whomwah/rqrcode_core/releases) - [Commits](https://github.com/whomwah/rqrcode_core/commits) --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5fc2845215..16c9ff407e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -314,7 +314,7 @@ GEM rqrcode (1.1.2) chunky_png (~> 1.0) rqrcode_core (~> 0.1) - rqrcode_core (0.1.1) + rqrcode_core (0.1.2) rspec (3.9.0) rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) From db337b10ee2af66f464082ca24bb33536da5fbde Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 29 Apr 2020 16:24:53 +0200 Subject: [PATCH 0857/1830] FIX: correctly hides timeline scroller for short posts (#9581) * FIX: correctly hides timeline scroller for short posts * fix linting --- .../discourse/app/mixins/docking.js | 5 +- .../discourse/app/widgets/topic-timeline.js | 64 +++++++++++-------- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/app/assets/javascripts/discourse/app/mixins/docking.js b/app/assets/javascripts/discourse/app/mixins/docking.js index 3df9f80eda..63e40aa032 100644 --- a/app/assets/javascripts/discourse/app/mixins/docking.js +++ b/app/assets/javascripts/discourse/app/mixins/docking.js @@ -1,5 +1,5 @@ import Mixin from "@ember/object/mixin"; -import { debounce } from "@ember/runloop"; +import { later, debounce } from "@ember/runloop"; const helper = { offset() { @@ -32,7 +32,8 @@ export default Mixin.create({ $(window).bind("scroll.discourse-dock", this.queueDockCheck); $(document).bind("touchmove.discourse-dock", this.queueDockCheck); - this.dockCheck(helper); + // dockCheck might happen too early on full page refresh + later(this, this.safeDockCheck, 50); }, willDestroyElement() { diff --git a/app/assets/javascripts/discourse/app/widgets/topic-timeline.js b/app/assets/javascripts/discourse/app/widgets/topic-timeline.js index 5f3cabfb8e..b74f691bfb 100644 --- a/app/assets/javascripts/discourse/app/widgets/topic-timeline.js +++ b/app/assets/javascripts/discourse/app/widgets/topic-timeline.js @@ -518,32 +518,46 @@ export default createWidget("topic-timeline", { result.push(this.attach("timeline-controls", attrs)); - const bottomAge = relativeAge(new Date(topic.last_posted_at), { - addAgo: true, - defaultFormat: timelineDate - }); - let scroller = [ - h( - "div.timeline-date-wrapper", - this.attach("link", { - className: "start-date", - rawLabel: timelineDate(createdAt), - action: "jumpTop" - }) - ), - this.attach("timeline-scrollarea", attrs), - h( - "div.timeline-date-wrapper", - this.attach("link", { - className: "now-date", - rawLabel: bottomAge, - action: "jumpBottom" - }) - ) - ]; + let displayTimeLineScrollArea = true; + if (!attrs.mobileView) { + const streamLength = attrs.topic.get("postStream.stream.length"); - result.push(h("div.timeline-scrollarea-wrapper", scroller)); - result.push(this.attach("timeline-footer-controls", attrs)); + if (streamLength < 2) { + const postsWrapper = document.querySelector(".posts-wrapper"); + if (postsWrapper && postsWrapper.offsetHeight < 1000) { + displayTimeLineScrollArea = false; + } + } + } + + if (displayTimeLineScrollArea) { + const bottomAge = relativeAge(new Date(topic.last_posted_at), { + addAgo: true, + defaultFormat: timelineDate + }); + let scroller = [ + h( + "div.timeline-date-wrapper", + this.attach("link", { + className: "start-date", + rawLabel: timelineDate(createdAt), + action: "jumpTop" + }) + ), + this.attach("timeline-scrollarea", attrs), + h( + "div.timeline-date-wrapper", + this.attach("link", { + className: "now-date", + rawLabel: bottomAge, + action: "jumpBottom" + }) + ) + ]; + + result.push(h("div.timeline-scrollarea-wrapper", scroller)); + result.push(this.attach("timeline-footer-controls", attrs)); + } return result; } From 9dccf4f3b84bdff7e79af39399d0a9ecfecabe1d Mon Sep 17 00:00:00 2001 From: Joshua Rosenfeld Date: Wed, 29 Apr 2020 10:37:06 -0400 Subject: [PATCH 0858/1830] FIX: Copyedit for "You were logged out" modal (#9584) See https://meta.discourse.org/t/-/149596 --- app/assets/javascripts/discourse/app/initializers/logout.js | 2 +- config/locales/client.en.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/app/initializers/logout.js b/app/assets/javascripts/discourse/app/initializers/logout.js index 571057ca83..067dd1e538 100644 --- a/app/assets/javascripts/discourse/app/initializers/logout.js +++ b/app/assets/javascripts/discourse/app/initializers/logout.js @@ -21,7 +21,7 @@ export default { bootbox.dialog( I18n.t("logout"), { - label: I18n.t("refresh"), + label: I18n.t("home"), callback: logout }, { diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index cc828b2a0e..da09ba9c9e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1398,6 +1398,7 @@ en: assets_changed_confirm: "This site was just updated. Refresh now for the latest version?" logout: "You were logged out." refresh: "Refresh" + home: "Home" read_only_mode: enabled: "This site is in read only mode. Please continue to browse, but replying, likes, and other actions are disabled for now." login_disabled: "Login is disabled while the site is in read only mode." From 3ec21b4124954dc57c872766fbafc95c9c708de1 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 29 Apr 2020 10:56:44 -0400 Subject: [PATCH 0859/1830] SECURITY: Update onebox to add rel="noopener" --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 16c9ff407e..f561205552 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -241,7 +241,7 @@ GEM omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack - onebox (1.9.27.1) + onebox (1.9.27.2) addressable (~> 2.7.0) htmlentities (~> 4.3) multi_json (~> 1.11) From cbb27241c428781eff06239e73ec03d5b7b24432 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 29 Apr 2020 12:18:21 -0400 Subject: [PATCH 0860/1830] DEV: Make `discourse-common` an Ember addon. (#9578) This is to help with the migration to Ember CLI. In the current running version of Discourse everything should be the same as before, just with a few extra files that are not used. However, using Ember CLI this can be installed as an Ember addon. Co-Authored-By: Jarek Radosz --- .git-blame-ignore-revs | 3 - app/assets/javascripts/application.js | 2 +- .../discourse-common/addon/.gitkeep | 0 .../addon/config/environment.js | 3 + .../{ => addon}/helpers/bound-i18n.js | 0 .../helpers/component-for-collection.js | 0 .../{ => addon}/helpers/component-for-row.js | 0 .../{ => addon}/helpers/d-icon.js | 0 .../{ => addon}/helpers/fa-icon.js | 0 .../{ => addon}/helpers/get-url.js | 0 .../{ => addon}/helpers/html-safe.js | 0 .../{ => addon}/helpers/i18n.js | 0 .../{ => addon}/helpers/popular-themes.js | 0 .../{ => addon}/lib/attribute-hook.js | 0 .../{ => addon}/lib/deprecated.js | 0 .../{ => addon}/lib/get-owner.js | 0 .../{ => addon}/lib/get-url.js | 0 .../{ => addon}/lib/helpers.js | 0 .../{ => addon}/lib/icon-library.js | 0 .../{ => addon}/lib/raw-handlebars-helpers.js | 0 .../{ => addon}/lib/raw-handlebars.js | 0 .../{ => addon}/mixins/focus-event.js | 0 .../discourse-common/{ => addon}/resolver.js | 0 .../{ => addon}/utils/decorator-alias.js | 0 .../{ => addon}/utils/decorators.js | 0 .../{ => addon}/utils/extract-value.js | 0 .../{ => addon}/utils/handle-descriptor.js | 0 .../{ => addon}/utils/is-descriptor.js | 0 .../{ => addon}/utils/macro-alias.js | 0 .../javascripts/discourse-common/app/.gitkeep | 0 .../discourse-common/config/ember-try.js | 89 + .../discourse-common/config/environment.js | 6 +- .../discourse-common/ember-cli-build.js | 9 + .../javascripts/discourse-common/index.js | 5 + .../javascripts/discourse-common/package.json | 54 + .../discourse-common/vendor/.gitkeep | 0 .../javascripts/discourse-common/yarn.lock | 10485 ++++++++++++++++ app/assets/javascripts/wizard-application.js | 3 +- lib/discourse_js_processor.rb | 2 +- lib/freedom_patches/raw_handlebars.rb | 2 +- package.json | 2 +- 41 files changed, 10654 insertions(+), 11 deletions(-) create mode 100644 app/assets/javascripts/discourse-common/addon/.gitkeep create mode 100644 app/assets/javascripts/discourse-common/addon/config/environment.js rename app/assets/javascripts/discourse-common/{ => addon}/helpers/bound-i18n.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/component-for-collection.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/component-for-row.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/d-icon.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/fa-icon.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/get-url.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/html-safe.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/i18n.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/helpers/popular-themes.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/attribute-hook.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/deprecated.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/get-owner.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/get-url.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/helpers.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/icon-library.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/raw-handlebars-helpers.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/lib/raw-handlebars.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/mixins/focus-event.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/resolver.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/utils/decorator-alias.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/utils/decorators.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/utils/extract-value.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/utils/handle-descriptor.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/utils/is-descriptor.js (100%) rename app/assets/javascripts/discourse-common/{ => addon}/utils/macro-alias.js (100%) create mode 100644 app/assets/javascripts/discourse-common/app/.gitkeep create mode 100644 app/assets/javascripts/discourse-common/config/ember-try.js create mode 100644 app/assets/javascripts/discourse-common/ember-cli-build.js create mode 100644 app/assets/javascripts/discourse-common/index.js create mode 100644 app/assets/javascripts/discourse-common/package.json create mode 100644 app/assets/javascripts/discourse-common/vendor/.gitkeep create mode 100644 app/assets/javascripts/discourse-common/yarn.lock diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 81d5a2fff5..e848bdcf4c 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -23,9 +23,6 @@ acc5cbdf8ecb9293a0fa9474ee73baf499c02428 # Rename wizard from es6 -> js 1ac02422011f89716ab27250d39b0e0212e03892 -# Rename discourse-common es6 -> js -167503ca4824e37a2e93d74b3f50271556d0ba8e - # Rename some root files 11938d58d4b1bea1ff43306450da7b24f05db0a diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 86d34b4a82..489768d27d 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,4 +1,4 @@ -//= require_tree ./discourse-common +//= require_tree ./discourse-common/addon //= require ./polyfills //= require_tree ./select-kit //= require ./discourse/app/app diff --git a/app/assets/javascripts/discourse-common/addon/.gitkeep b/app/assets/javascripts/discourse-common/addon/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/javascripts/discourse-common/addon/config/environment.js b/app/assets/javascripts/discourse-common/addon/config/environment.js new file mode 100644 index 0000000000..18ce3cc976 --- /dev/null +++ b/app/assets/javascripts/discourse-common/addon/config/environment.js @@ -0,0 +1,3 @@ +export const INPUT_DELAY = 250; + +export default { environment: Ember.testing ? "test" : "development" }; diff --git a/app/assets/javascripts/discourse-common/helpers/bound-i18n.js b/app/assets/javascripts/discourse-common/addon/helpers/bound-i18n.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/bound-i18n.js rename to app/assets/javascripts/discourse-common/addon/helpers/bound-i18n.js diff --git a/app/assets/javascripts/discourse-common/helpers/component-for-collection.js b/app/assets/javascripts/discourse-common/addon/helpers/component-for-collection.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/component-for-collection.js rename to app/assets/javascripts/discourse-common/addon/helpers/component-for-collection.js diff --git a/app/assets/javascripts/discourse-common/helpers/component-for-row.js b/app/assets/javascripts/discourse-common/addon/helpers/component-for-row.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/component-for-row.js rename to app/assets/javascripts/discourse-common/addon/helpers/component-for-row.js diff --git a/app/assets/javascripts/discourse-common/helpers/d-icon.js b/app/assets/javascripts/discourse-common/addon/helpers/d-icon.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/d-icon.js rename to app/assets/javascripts/discourse-common/addon/helpers/d-icon.js diff --git a/app/assets/javascripts/discourse-common/helpers/fa-icon.js b/app/assets/javascripts/discourse-common/addon/helpers/fa-icon.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/fa-icon.js rename to app/assets/javascripts/discourse-common/addon/helpers/fa-icon.js diff --git a/app/assets/javascripts/discourse-common/helpers/get-url.js b/app/assets/javascripts/discourse-common/addon/helpers/get-url.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/get-url.js rename to app/assets/javascripts/discourse-common/addon/helpers/get-url.js diff --git a/app/assets/javascripts/discourse-common/helpers/html-safe.js b/app/assets/javascripts/discourse-common/addon/helpers/html-safe.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/html-safe.js rename to app/assets/javascripts/discourse-common/addon/helpers/html-safe.js diff --git a/app/assets/javascripts/discourse-common/helpers/i18n.js b/app/assets/javascripts/discourse-common/addon/helpers/i18n.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/i18n.js rename to app/assets/javascripts/discourse-common/addon/helpers/i18n.js diff --git a/app/assets/javascripts/discourse-common/helpers/popular-themes.js b/app/assets/javascripts/discourse-common/addon/helpers/popular-themes.js similarity index 100% rename from app/assets/javascripts/discourse-common/helpers/popular-themes.js rename to app/assets/javascripts/discourse-common/addon/helpers/popular-themes.js diff --git a/app/assets/javascripts/discourse-common/lib/attribute-hook.js b/app/assets/javascripts/discourse-common/addon/lib/attribute-hook.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/attribute-hook.js rename to app/assets/javascripts/discourse-common/addon/lib/attribute-hook.js diff --git a/app/assets/javascripts/discourse-common/lib/deprecated.js b/app/assets/javascripts/discourse-common/addon/lib/deprecated.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/deprecated.js rename to app/assets/javascripts/discourse-common/addon/lib/deprecated.js diff --git a/app/assets/javascripts/discourse-common/lib/get-owner.js b/app/assets/javascripts/discourse-common/addon/lib/get-owner.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/get-owner.js rename to app/assets/javascripts/discourse-common/addon/lib/get-owner.js diff --git a/app/assets/javascripts/discourse-common/lib/get-url.js b/app/assets/javascripts/discourse-common/addon/lib/get-url.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/get-url.js rename to app/assets/javascripts/discourse-common/addon/lib/get-url.js diff --git a/app/assets/javascripts/discourse-common/lib/helpers.js b/app/assets/javascripts/discourse-common/addon/lib/helpers.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/helpers.js rename to app/assets/javascripts/discourse-common/addon/lib/helpers.js diff --git a/app/assets/javascripts/discourse-common/lib/icon-library.js b/app/assets/javascripts/discourse-common/addon/lib/icon-library.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/icon-library.js rename to app/assets/javascripts/discourse-common/addon/lib/icon-library.js diff --git a/app/assets/javascripts/discourse-common/lib/raw-handlebars-helpers.js b/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars-helpers.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/raw-handlebars-helpers.js rename to app/assets/javascripts/discourse-common/addon/lib/raw-handlebars-helpers.js diff --git a/app/assets/javascripts/discourse-common/lib/raw-handlebars.js b/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js similarity index 100% rename from app/assets/javascripts/discourse-common/lib/raw-handlebars.js rename to app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js diff --git a/app/assets/javascripts/discourse-common/mixins/focus-event.js b/app/assets/javascripts/discourse-common/addon/mixins/focus-event.js similarity index 100% rename from app/assets/javascripts/discourse-common/mixins/focus-event.js rename to app/assets/javascripts/discourse-common/addon/mixins/focus-event.js diff --git a/app/assets/javascripts/discourse-common/resolver.js b/app/assets/javascripts/discourse-common/addon/resolver.js similarity index 100% rename from app/assets/javascripts/discourse-common/resolver.js rename to app/assets/javascripts/discourse-common/addon/resolver.js diff --git a/app/assets/javascripts/discourse-common/utils/decorator-alias.js b/app/assets/javascripts/discourse-common/addon/utils/decorator-alias.js similarity index 100% rename from app/assets/javascripts/discourse-common/utils/decorator-alias.js rename to app/assets/javascripts/discourse-common/addon/utils/decorator-alias.js diff --git a/app/assets/javascripts/discourse-common/utils/decorators.js b/app/assets/javascripts/discourse-common/addon/utils/decorators.js similarity index 100% rename from app/assets/javascripts/discourse-common/utils/decorators.js rename to app/assets/javascripts/discourse-common/addon/utils/decorators.js diff --git a/app/assets/javascripts/discourse-common/utils/extract-value.js b/app/assets/javascripts/discourse-common/addon/utils/extract-value.js similarity index 100% rename from app/assets/javascripts/discourse-common/utils/extract-value.js rename to app/assets/javascripts/discourse-common/addon/utils/extract-value.js diff --git a/app/assets/javascripts/discourse-common/utils/handle-descriptor.js b/app/assets/javascripts/discourse-common/addon/utils/handle-descriptor.js similarity index 100% rename from app/assets/javascripts/discourse-common/utils/handle-descriptor.js rename to app/assets/javascripts/discourse-common/addon/utils/handle-descriptor.js diff --git a/app/assets/javascripts/discourse-common/utils/is-descriptor.js b/app/assets/javascripts/discourse-common/addon/utils/is-descriptor.js similarity index 100% rename from app/assets/javascripts/discourse-common/utils/is-descriptor.js rename to app/assets/javascripts/discourse-common/addon/utils/is-descriptor.js diff --git a/app/assets/javascripts/discourse-common/utils/macro-alias.js b/app/assets/javascripts/discourse-common/addon/utils/macro-alias.js similarity index 100% rename from app/assets/javascripts/discourse-common/utils/macro-alias.js rename to app/assets/javascripts/discourse-common/addon/utils/macro-alias.js diff --git a/app/assets/javascripts/discourse-common/app/.gitkeep b/app/assets/javascripts/discourse-common/app/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/javascripts/discourse-common/config/ember-try.js b/app/assets/javascripts/discourse-common/config/ember-try.js new file mode 100644 index 0000000000..bcae42888f --- /dev/null +++ b/app/assets/javascripts/discourse-common/config/ember-try.js @@ -0,0 +1,89 @@ +"use strict"; + +const getChannelURL = require("ember-source-channel-url"); + +module.exports = async function() { + return { + useYarn: true, + scenarios: [ + { + name: "ember-lts-3.8", + npm: { + devDependencies: { + "ember-source": "~3.8.0" + } + } + }, + { + name: "ember-lts-3.12", + npm: { + devDependencies: { + "ember-source": "~3.12.0" + } + } + }, + { + name: "ember-release", + npm: { + devDependencies: { + "ember-source": await getChannelURL("release") + } + } + }, + { + name: "ember-beta", + npm: { + devDependencies: { + "ember-source": await getChannelURL("beta") + } + } + }, + { + name: "ember-canary", + npm: { + devDependencies: { + "ember-source": await getChannelURL("canary") + } + } + }, + // The default `.travis.yml` runs this scenario via `yarn test`, + // not via `ember try`. It's still included here so that running + // `ember try:each` manually or from a customized CI config will run it + // along with all the other scenarios. + { + name: "ember-default", + npm: { + devDependencies: {} + } + }, + { + name: "ember-default-with-jquery", + env: { + EMBER_OPTIONAL_FEATURES: JSON.stringify({ + "jquery-integration": true + }) + }, + npm: { + devDependencies: { + "@ember/jquery": "^0.5.1" + } + } + }, + { + name: "ember-classic", + env: { + EMBER_OPTIONAL_FEATURES: JSON.stringify({ + "application-template-wrapper": true, + "default-async-observers": false, + "template-only-glimmer-components": false + }) + }, + npm: { + ember: { + edition: "classic" + } + } + } + ] + }; +}; diff --git a/app/assets/javascripts/discourse-common/config/environment.js b/app/assets/javascripts/discourse-common/config/environment.js index 18ce3cc976..352093f4ed 100644 --- a/app/assets/javascripts/discourse-common/config/environment.js +++ b/app/assets/javascripts/discourse-common/config/environment.js @@ -1,3 +1,5 @@ -export const INPUT_DELAY = 250; +"use strict"; -export default { environment: Ember.testing ? "test" : "development" }; +module.exports = function(/* environment, appConfig */) { + return {}; +}; diff --git a/app/assets/javascripts/discourse-common/ember-cli-build.js b/app/assets/javascripts/discourse-common/ember-cli-build.js new file mode 100644 index 0000000000..cbf921270c --- /dev/null +++ b/app/assets/javascripts/discourse-common/ember-cli-build.js @@ -0,0 +1,9 @@ +"use strict"; + +const EmberAddon = require("ember-cli/lib/broccoli/ember-addon"); + +module.exports = function(defaults) { + let app = new EmberAddon(defaults, {}); + + return app.toTree(); +}; diff --git a/app/assets/javascripts/discourse-common/index.js b/app/assets/javascripts/discourse-common/index.js new file mode 100644 index 0000000000..e8db57f915 --- /dev/null +++ b/app/assets/javascripts/discourse-common/index.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + name: require("./package").name +}; diff --git a/app/assets/javascripts/discourse-common/package.json b/app/assets/javascripts/discourse-common/package.json new file mode 100644 index 0000000000..f56ec8cce4 --- /dev/null +++ b/app/assets/javascripts/discourse-common/package.json @@ -0,0 +1,54 @@ +{ + "name": "discourse-common", + "version": "1.0.0", + "description": "Shared code between discourse apps", + "author": "Discourse", + "license": "GPLv2", + "keywords": [ + "ember-addon" + ], + "repository": "", + "license": "", + "author": "", + "scripts": { + "build": "ember build", + "lint:hbs": "ember-template-lint .", + "lint:js": "eslint .", + "start": "ember serve" + }, + "dependencies": { + "ember-cli-babel": "^7.13.0", + "ember-cli-htmlbars": "^4.2.0" + }, + "devDependencies": { + "@ember/optional-features": "^1.1.0", + "@glimmer/component": "^1.0.0", + "babel-eslint": "^10.0.3", + "broccoli-asset-rev": "^3.0.0", + "ember-auto-import": "^1.5.3", + "ember-cli": "~3.15.2", + "ember-cli-dependency-checker": "^3.2.0", + "ember-cli-eslint": "^5.1.0", + "ember-cli-inject-live-reload": "^2.0.1", + "ember-cli-sri": "^2.1.1", + "ember-cli-template-lint": "^1.0.0-beta.3", + "ember-cli-uglify": "^3.0.0", + "ember-disable-prototype-extensions": "^1.1.3", + "ember-export-application-global": "^2.0.1", + "ember-load-initializers": "^2.1.1", + "ember-maybe-import-regenerator": "^0.1.6", + "ember-resolver": "^7.0.0", + "ember-source": "~3.15.0", + "ember-source-channel-url": "^2.0.1", + "ember-try": "^1.4.0", + "eslint-plugin-ember": "^7.7.1", + "eslint-plugin-node": "^10.0.0", + "loader.js": "^4.7.0" + }, + "engines": { + "node": "8.* || >= 10.*" + }, + "ember": { + "edition": "octane" + } +} diff --git a/app/assets/javascripts/discourse-common/vendor/.gitkeep b/app/assets/javascripts/discourse-common/vendor/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/javascripts/discourse-common/yarn.lock b/app/assets/javascripts/discourse-common/yarn.lock new file mode 100644 index 0000000000..fc099710ca --- /dev/null +++ b/app/assets/javascripts/discourse-common/yarn.lock @@ -0,0 +1,10485 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + +"@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c" + integrity sha512-zeFQrr+284Ekvd9e7KAX954LkapWiOmQtsfHirhxqfdlX6MEC32iRE+pqUGlYIBchdevaCwvzxWGSy/YBNI85g== + dependencies: + browserslist "^4.9.1" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@^7.1.6", "@babel/core@^7.2.2", "@babel/core@^7.3.4", "@babel/core@^7.7.2", "@babel/core@^7.8.3", "@babel/core@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e" + integrity sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.0" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.0" + "@babel/parser" "^7.9.0" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.9.0", "@babel/generator@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9" + integrity sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ== + dependencies: + "@babel/types" "^7.9.5" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-compilation-targets@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.8.7.tgz#dac1eea159c0e4bd46e309b5a1b04a66b53c1dde" + integrity sha512-4mWm8DCK2LugIS+p1yArqvG1Pf162upsIsjE7cNBjez+NjliQpVhj20obE520nao0o14DaTnFJv+Fw5a0JpoUw== + dependencies: + "@babel/compat-data" "^7.8.6" + browserslist "^4.9.1" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-class-features-plugin@^7.5.5", "@babel/helper-create-class-features-plugin@^7.8.3": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.9.5.tgz#79753d44017806b481017f24b02fd4113c7106ea" + integrity sha512-IipaxGaQmW4TfWoXdqjY0TzoXQ1HRS0kPpEgvjosb3u7Uedcq297xFqDQiCcQtRRwzIMif+N1MLVI8C5a4/PAA== + dependencies: + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + +"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.7.0" + +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== + dependencies: + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" + integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.9.5" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== + dependencies: + lodash "^4.17.13" + +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8" + integrity sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.8.6" + "@babel/types" "^7.8.6" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" + integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== + +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f" + integrity sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.9.0" + "@babel/types" "^7.9.0" + +"@babel/highlight@^7.8.3": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" + integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.3.4", "@babel/parser@^7.4.5", "@babel/parser@^7.7.0", "@babel/parser@^7.8.6", "@babel/parser@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8" + integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA== + +"@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.8.3.tgz#5e06654af5cd04b608915aada9b2a6788004464e" + integrity sha512-EqFhbo7IosdgPgZggHaNObkmO1kNUe3slaKu54d5OWvy+p9QIKOzK1GAEpAIsZtWVtPXUHSMcT4smvDrCfY4AA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-proposal-decorators@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.8.3.tgz#2156860ab65c5abf068c3f67042184041066543e" + integrity sha512-e3RvdvS4qPJVTe288DlXjwKflpfy1hr0j5dz5WpIYYeP7vQZg2WfAEIp8k5/Lwis/m5REXEteIz6rrcDtXXG7w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-decorators" "^7.8.3" + +"@babel/plugin-proposal-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" + integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + +"@babel/plugin-proposal-object-rest-spread@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.5.tgz#3fd65911306d8746014ec0d0cf78f0e39a149116" + integrity sha512-VP2oXvAf7KCYTthbUHwBlewbl1Iq059f6seJGsxMizaCdgHIeczOr7FBqELhSqfkIl04Fi8okzWzl63UKbQmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.9.5" + +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" + integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.8" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-decorators@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.8.3.tgz#8d2c15a9f1af624b0025f961682a9d53d3001bda" + integrity sha512-8Hg4dNNT9/LcA1zQlfwuKR8BUc/if7Q7NkTam9sGTcJphLwpf2g4S42uhspQrIrR+dpzE0dtTqBVFoHl8GtnnQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-dynamic-import@^7.2.0", "@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" + integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-typescript@^7.2.0", "@babel/plugin-syntax-typescript@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.8.3.tgz#c1f659dda97711a569cef75275f7e15dcaa6cabc" + integrity sha512-GO1MQ/SGGGoiEXY0e0bSpHimJvxqB7lktLLIq2pv8xG7WZ8IMEle74jIe1FhprHBWjwjZtXHkycDLZXIWM5Wfg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.6.2", "@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz#800597ddb8aefc2c293ed27459c1fcc935a26c2c" + integrity sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-destructuring@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz#72c97cf5f38604aea3abf3b935b0e17b1db76a50" + integrity sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" + integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-modules-amd@^7.5.0", "@babel/plugin-transform-modules-amd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.0.tgz#19755ee721912cf5bb04c07d50280af3484efef4" + integrity sha512-vZgDDF003B14O8zJy0XXLnPH4sg+9X5hFBBGN1V+B2rgrB+J2xIypSN6Rk9imB2hSTHQi5OHLrFWsZab1GMk+Q== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-commonjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.0.tgz#e3e72f4cbc9b4a260e30be0ea59bdf5a39748940" + integrity sha512-qzlCrLnKqio4SlgJ6FMMLBe4bySNis8DFn1VkGmOcxG9gqEyPIOzeQrA//u0HAKrWpJlpZbZMPB1n/OPa4+n8g== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-systemjs@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.0.tgz#e9fd46a296fc91e009b64e07ddaa86d6f0edeb90" + integrity sha512-FsiAv/nao/ud2ZWy4wFacoLOm5uxl0ExSQ7ErvP7jpoihLR6Cq90ilOFyX9UXct3rbtKsAiZ9kFt5XGfPe/5SQ== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.0" + +"@babel/plugin-transform-modules-umd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" + integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + +"@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-assign@^7.2.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.8.3.tgz#dc3b8dd50ef03837868a37b7df791f64f288538e" + integrity sha512-i3LuN8tPDqUCRFu3dkzF2r1Nx0jp4scxtm7JxtIqI9he9Vk20YD+/zshdzR9JLsoBMlJlNR82a62vQExNEVx/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz#173b265746f5e15b2afe527eeda65b73623a0795" + integrity sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-runtime@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.9.0.tgz#45468c0ae74cc13204e1d3b1f4ce6ee83258af0b" + integrity sha512-pUu9VSf3kI1OqbWINQ7MaugnitRss1z533436waNXp+0N3ur3zfut37sXiQMxkuCF4VUjwZucen/quskCh7NHw== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + resolve "^1.8.1" + semver "^5.5.1" + +"@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + +"@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typeof-symbol@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typescript@^7.9.0": + version "7.9.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.9.4.tgz#4bb4dde4f10bbf2d787fce9707fb09b483e33359" + integrity sha512-yeWeUkKx2auDbSxRe8MusAG+n4m9BFY/v+lPjmQDgOFX5qnySkUY5oXzkp6FwPdsYqnKay6lorXYdC0n3bZO7w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-typescript" "^7.8.3" + +"@babel/plugin-transform-typescript@~7.4.0": + version "7.4.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.4.5.tgz#ab3351ba35307b79981993536c93ff8be050ba28" + integrity sha512-RPB/YeGr4ZrFKNwfuQRlMf2lxoCUaU01MTw39/OFE/RiL8HDjtn68BwEPft1P7JN4akyEmjGWAMNldOV7o9V2g== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" + +"@babel/plugin-transform-typescript@~7.5.0": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.5.5.tgz#6d862766f09b2da1cb1f7d505fe2aedab6b7d4b8" + integrity sha512-pehKf4m640myZu5B2ZviLaiBlxMCjSZ1qTEO459AXKX5GnPueyulJeCqZFs1nz/Ya2dDzXQ1NxZ/kKNWyD4h6w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.5.5" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.2.0" + +"@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/polyfill@^7.8.3", "@babel/polyfill@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.8.7.tgz#151ec24c7135481336168c3bd8b8bf0cf91c032f" + integrity sha512-LeSfP9bNZH2UOZgcGcZ0PIHUt1ZuHub1L3CVmEyqLxCeDLm4C5Gi8jRH8ZX2PNpDhQCo0z6y/+DIs2JlliXW8w== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.0.0", "@babel/preset-env@^7.9.0": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.5.tgz#8ddc76039bc45b774b19e2fc548f6807d8a8919f" + integrity sha512-eWGYeADTlPJH+wq1F0wNfPbVS1w1wtmMJiYk55Td5Yu28AsdR9AsC97sZ0Qq8fHqQuslVSIYSGJMcblr345GfQ== + dependencies: + "@babel/compat-data" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.5" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.5" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.9.5" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-modules-commonjs" "^7.9.0" + "@babel/plugin-transform-modules-systemjs" "^7.9.0" + "@babel/plugin-transform-modules-umd" "^7.9.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.9.5" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.5" + browserslist "^4.9.1" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-modules@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" + integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.8.4", "@babel/runtime@^7.9.0": + version "7.9.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06" + integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" + +"@babel/traverse@^7.1.6", "@babel/traverse@^7.2.4", "@babel/traverse@^7.3.4", "@babel/traverse@^7.4.5", "@babel/traverse@^7.7.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.6", "@babel/traverse@^7.9.0": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.5.tgz#6e7c56b44e2ac7011a948c21e283ddd9d9db97a2" + integrity sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.5" + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.9.0" + "@babel/types" "^7.9.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.1.6", "@babel/types@^7.3.2", "@babel/types@^7.3.4", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" + integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== + dependencies: + "@babel/helper-validator-identifier" "^7.9.5" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@ember-data/rfc395-data@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@ember-data/rfc395-data/-/rfc395-data-0.0.4.tgz#ecb86efdf5d7733a76ff14ea651a1b0ed1f8a843" + integrity sha512-tGRdvgC9/QMQSuSuJV45xoyhI0Pzjm7A9o/MVVA3HakXIImJbbzx/k/6dO9CUEQXIyS2y0fW6C1XaYOG7rY0FQ== + +"@ember/edition-utils@^1.1.1", "@ember/edition-utils@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ember/edition-utils/-/edition-utils-1.2.0.tgz#a039f542dc14c8e8299c81cd5abba95e2459cfa6" + integrity sha512-VmVq/8saCaPdesQmftPqbFtxJWrzxNGSQ+e8x8LLe3Hjm36pJ04Q8LeORGZkAeOhldoUX9seLGmSaHeXkIqoog== + +"@ember/optional-features@^1.1.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ember/optional-features/-/optional-features-1.3.0.tgz#d7da860417b85a56cec88419f30da5ee1dde2756" + integrity sha512-Lrfojy4xKwTX+J4EAylmxZY2TO6bQtP4Lg5C8/z2priVqiT0X5fVB1+4WQCJbRBetctO1lMDnqjmhWCVKB8bmQ== + dependencies: + chalk "^3.0.0" + ember-cli-version-checker "^3.1.3" + glob "^7.1.6" + inquirer "^7.0.1" + mkdirp "^0.5.1" + silent-error "^1.1.1" + util.promisify "^1.0.0" + +"@ember/test-helpers@^1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@ember/test-helpers/-/test-helpers-1.7.1.tgz#cc22a954b3b46856518f034bd492a74e0482389f" + integrity sha512-+ioumnanSRJzZ0ZH30FIkB0r41UhVyuWQ9R9Yp1phDWJQDLumxg+25WDr40relwcH6z0Cn6LIEzeTVujO/0Rww== + dependencies: + broccoli-debug "^0.6.5" + broccoli-funnel "^2.0.2" + ember-assign-polyfill "^2.6.0" + ember-cli-babel "^7.7.3" + ember-cli-htmlbars-inline-precompile "^2.1.0" + ember-test-waiters "^1.1.1" + +"@embroider/core@0.4.3", "@embroider/core@^0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@embroider/core/-/core-0.4.3.tgz#117973b9761d68aee14d820bbaefeb05d5984ba8" + integrity sha512-n24WU/dGuGDqZrljWoX8raK2wFX3R8iJG0rfCWx+1kW87IvB+ZgS3j4KiZ/S788BA07udrYsrgecYnciG2bBMg== + dependencies: + "@babel/core" "^7.2.2" + "@babel/parser" "^7.3.4" + "@babel/plugin-syntax-dynamic-import" "^7.2.0" + "@babel/traverse" "^7.3.4" + "@babel/types" "^7.3.4" + "@embroider/macros" "0.4.3" + assert-never "^1.1.0" + babel-plugin-syntax-dynamic-import "^6.18.0" + broccoli-persistent-filter "^2.2.2" + broccoli-plugin "^1.3.0" + broccoli-source "^1.1.0" + debug "^3.1.0" + fast-sourcemap-concat "^1.4.0" + filesize "^4.1.2" + fs-extra "^7.0.1" + fs-tree-diff "^2.0.0" + handlebars "^4.0.11" + js-string-escape "^1.0.1" + jsdom "^12.0.0" + json-stable-stringify "^1.0.1" + lodash "^4.17.10" + pkg-up "^2.0.0" + resolve "^1.8.1" + resolve-package-path "^1.2.2" + semver "^5.5.0" + strip-bom "^3.0.0" + typescript-memoize "^1.0.0-alpha.3" + walk-sync "^1.1.3" + +"@embroider/macros@0.4.3": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@embroider/macros/-/macros-0.4.3.tgz#ea5604b8bd578520f15886a428a6c4fa9481abc0" + integrity sha512-vq/Ny2ULpKxq60Sv5usSrz651dXFM5phP/O5G5MWDY8YOodIkRLGqtub34sB0OmwxpCuTntUzl9P/I4wkyQ3Kw== + dependencies: + "@babel/core" "^7.2.2" + "@babel/traverse" "^7.2.4" + "@babel/types" "^7.3.2" + "@embroider/core" "0.4.3" + resolve "^1.8.1" + semver "^5.6.0" + +"@glimmer/component@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@glimmer/component/-/component-1.0.0.tgz#f9052c8e99fb7b3d48d27c65891c5f0e59084a82" + integrity sha512-1ERZYNLZRuC8RYbcfkJeAWn3Ly7W2VdoHLQIHCmhQH/m7ubkNOdLQcTnUzje7OnRUs9EJ6DjfoN57XRX9Ux4rA== + dependencies: + "@glimmer/di" "^0.1.9" + "@glimmer/env" "^0.1.7" + "@glimmer/util" "^0.44.0" + broccoli-file-creator "^2.1.1" + broccoli-merge-trees "^3.0.2" + ember-cli-babel "^7.7.3" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.1.0" + ember-cli-typescript "3.0.0" + ember-compatibility-helpers "^1.1.2" + +"@glimmer/di@^0.1.9": + version "0.1.11" + resolved "https://registry.yarnpkg.com/@glimmer/di/-/di-0.1.11.tgz#a6878c07a13a2c2c76fcde598a5c97637bfc4280" + integrity sha1-poeMB6E6LCx2/N5ZilyXY3v8QoA= + +"@glimmer/env@0.1.7", "@glimmer/env@^0.1.7": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@glimmer/env/-/env-0.1.7.tgz#fd2d2b55a9029c6b37a6c935e8c8871ae70dfa07" + integrity sha1-/S0rVakCnGs3psk16MiHGucN+gc= + +"@glimmer/interfaces@^0.47.9": + version "0.47.9" + resolved "https://registry.yarnpkg.com/@glimmer/interfaces/-/interfaces-0.47.9.tgz#4c50b5343815045318bba38915f780ae39f14590" + integrity sha512-xne80DHkPC70u08LKV9g0+PboAmIw0A+vDXjJXMrDoRcNzCR4dXR6nvKD/Een+wbwwBaRawCIn45Rnk5+Dyvrg== + dependencies: + "@simple-dom/interface" "^1.4.0" + +"@glimmer/syntax@^0.47.9": + version "0.47.9" + resolved "https://registry.yarnpkg.com/@glimmer/syntax/-/syntax-0.47.9.tgz#f3d141efc97f601928335771721d1f27eb1ed7d2" + integrity sha512-ld3x2bTkAr/BXOkI1b3cDVBwMl0BTYtBNKODks0Fi/1DLx+F1jl4abpKJ5cww1k2iQ75jgG31IhBwb7YC2PmFA== + dependencies: + "@glimmer/interfaces" "^0.47.9" + "@glimmer/util" "^0.47.9" + handlebars "^4.5.1" + simple-html-tokenizer "^0.5.9" + +"@glimmer/util@^0.44.0": + version "0.44.0" + resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.44.0.tgz#45df98d73812440206ae7bda87cfe04aaae21ed9" + integrity sha512-duAsm30uVK9jSysElCbLyU6QQYO2X9iLDLBIBUcCqck9qN1o3tK2qWiHbGK5d6g8E2AJ4H88UrfElkyaJlGrwg== + +"@glimmer/util@^0.47.9": + version "0.47.9" + resolved "https://registry.yarnpkg.com/@glimmer/util/-/util-0.47.9.tgz#ad3085eba3975bcbc74d28aefc871becbe800417" + integrity sha512-MJEumozi3TKmx+kzTpqPdC0jLEIuWSS3JNdBXceqTGRZQGmE5Zxqd8ydH5KOYpsKSfURHGCi2vU6+X/Q4z2b6g== + dependencies: + "@glimmer/env" "0.1.7" + "@simple-dom/interface" "^1.4.0" + +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + +"@simple-dom/interface@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@simple-dom/interface/-/interface-1.4.0.tgz#e8feea579232017f89b0138e2726facda6fbb71f" + integrity sha512-l5qumKFWU0S+4ZzMaLXFU8tQZsicHEMEyAxI5kDFGhJsRqDwe0a7/iPA/GdxlGyDKseQQAgIz5kzU7eXTrlSpA== + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== + +"@types/body-parser@*": + version "1.19.0" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f" + integrity sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/chai-as-promised@^7.1.2": + version "7.1.2" + resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.2.tgz#2f564420e81eaf8650169e5a3a6b93e096e5068b" + integrity sha512-PO2gcfR3Oxa+u0QvECLe1xKXOqYTzCmWf0FhLhjREoW3fPAVamjihL7v1MOVLJLsnAMdLcjkfrs01yvDMwVK4Q== + dependencies: + "@types/chai" "*" + +"@types/chai@*", "@types/chai@^4.2.9": + version "4.2.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.11.tgz#d3614d6c5f500142358e6ed24e1bf16657536c50" + integrity sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== + +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + +"@types/connect@*": + version "3.4.33" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.33.tgz#31610c901eca573b8713c3330abc6e6b9f588546" + integrity sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A== + dependencies: + "@types/node" "*" + +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/express-serve-static-core@*": + version "4.17.5" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.5.tgz#a00ac7dadd746ae82477443e4d480a6a93ea083c" + integrity sha512-578YH5Lt88AKoADy0b2jQGwJtrBxezXtVe/MBqWXKZpqx91SnC0pVkVCcxcytz3lWW+cHBYDi3Ysh0WXc+rAYw== + dependencies: + "@types/node" "*" + "@types/range-parser" "*" + +"@types/express@^4.17.2": + version "4.17.6" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.6.tgz#6bce49e49570507b86ea1b07b806f04697fac45e" + integrity sha512-n/mr9tZI83kd4azlPG5y997C/M4DNABK9yErhFM6hKdym4kkmd9j0vtsJyjFIwfRBxtrxZtAfGZCNRIBMFLK5w== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "*" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/fs-extra@^5.0.5": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.1.0.tgz#2a325ef97901504a3828718c390d34b8426a10a1" + integrity sha512-AInn5+UBFIK9FK5xc9yP5e3TQSPNNgjHByqYcj9g5elVBnDQcQL7PlO1CIRy2gWlbwK7UPYqi7vRvFA44dCmYQ== + dependencies: + "@types/node" "*" + +"@types/glob@*", "@types/glob@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/mime@*": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" + integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== + +"@types/minimatch@*", "@types/minimatch@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/node@*": + version "13.13.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.4.tgz#1581d6c16e3d4803eb079c87d4ac893ee7501c2c" + integrity sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA== + +"@types/qs@*": + version "6.9.1" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.1.tgz#937fab3194766256ee09fcd40b781740758617e7" + integrity sha512-lhbQXx9HKZAPgBkISrBcmAcMpZsmpe/Cd/hY7LGZS5OfkySUBItnPZHgQPssWYUET8elF+yCFBbP1Q0RZPTdaw== + +"@types/range-parser@*": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" + integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== + +"@types/rimraf@^2.0.2": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.4.tgz#403887b0b53c6100a6c35d2ab24f6ccc042fec46" + integrity sha512-8gBudvllD2A/c0CcEX/BivIDorHFt5UI5m46TsNj8DjWCCTTZT74kEe4g+QsY7P/B9WdO98d82zZgXO/RQzu2Q== + dependencies: + "@types/glob" "*" + "@types/node" "*" + +"@types/serve-static@*": + version "1.13.3" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1" + integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== + dependencies: + "@types/express-serve-static-core" "*" + "@types/mime" "*" + +"@types/symlink-or-copy@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/symlink-or-copy/-/symlink-or-copy-1.2.0.tgz#4151a81b4052c80bc2becbae09f3a9ec010a9c7a" + integrity sha512-Lja2xYuuf2B3knEsga8ShbOdsfNOtzT73GyJmZyY7eGl2+ajOqrs8yM5ze0fsSoYwvA6bw7/Qr7OZ7PEEmYwWg== + +"@webassemblyjs/ast@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.7.11.tgz#b988582cafbb2b095e8b556526f30c90d057cace" + integrity sha512-ZEzy4vjvTzScC+SH8RBssQUawpaInUdMTYwYYLh54/s8TuT0gBLuyUnppKsVyZEi876VmmStKsUs28UxPgdvrA== + dependencies: + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + +"@webassemblyjs/floating-point-hex-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.7.11.tgz#a69f0af6502eb9a3c045555b1a6129d3d3f2e313" + integrity sha512-zY8dSNyYcgzNRNT666/zOoAyImshm3ycKdoLsyDw/Bwo6+/uktb7p4xyApuef1dwEBo/U/SYQzbGBvV+nru2Xg== + +"@webassemblyjs/helper-api-error@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.7.11.tgz#c7b6bb8105f84039511a2b39ce494f193818a32a" + integrity sha512-7r1qXLmiglC+wPNkGuXCvkmalyEstKVwcueZRP2GNC2PAvxbLYwLLPr14rcdJaE4UtHxQKfFkuDFuv91ipqvXg== + +"@webassemblyjs/helper-buffer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.7.11.tgz#3122d48dcc6c9456ed982debe16c8f37101df39b" + integrity sha512-MynuervdylPPh3ix+mKZloTcL06P8tenNH3sx6s0qE8SLR6DdwnfgA7Hc9NSYeob2jrW5Vql6GVlsQzKQCa13w== + +"@webassemblyjs/helper-code-frame@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.7.11.tgz#cf8f106e746662a0da29bdef635fcd3d1248364b" + integrity sha512-T8ESC9KMXFTXA5urJcyor5cn6qWeZ4/zLPyWeEXZ03hj/x9weSokGNkVCdnhSabKGYWxElSdgJ+sFa9G/RdHNw== + dependencies: + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/helper-fsm@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.7.11.tgz#df38882a624080d03f7503f93e3f17ac5ac01181" + integrity sha512-nsAQWNP1+8Z6tkzdYlXT0kxfa2Z1tRTARd8wYnc/e3Zv3VydVVnaeePgqUzFrpkGUyhUUxOl5ML7f1NuT+gC0A== + +"@webassemblyjs/helper-module-context@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.7.11.tgz#d874d722e51e62ac202476935d649c802fa0e209" + integrity sha512-JxfD5DX8Ygq4PvXDucq0M+sbUFA7BJAv/GGl9ITovqE+idGX+J3QSzJYz+LwQmL7fC3Rs+utvWoJxDb6pmC0qg== + +"@webassemblyjs/helper-wasm-bytecode@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.7.11.tgz#dd9a1e817f1c2eb105b4cf1013093cb9f3c9cb06" + integrity sha512-cMXeVS9rhoXsI9LLL4tJxBgVD/KMOKXuFqYb5oCJ/opScWpkCMEz9EJtkonaNcnLv2R3K5jIeS4TRj/drde1JQ== + +"@webassemblyjs/helper-wasm-section@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.7.11.tgz#9c9ac41ecf9fbcfffc96f6d2675e2de33811e68a" + integrity sha512-8ZRY5iZbZdtNFE5UFunB8mmBEAbSI3guwbrsCl4fWdfRiAcvqQpeqd5KHhSWLL5wuxo53zcaGZDBU64qgn4I4Q== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + +"@webassemblyjs/ieee754@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.7.11.tgz#c95839eb63757a31880aaec7b6512d4191ac640b" + integrity sha512-Mmqx/cS68K1tSrvRLtaV/Lp3NZWzXtOHUW2IvDvl2sihAwJh4ACE0eL6A8FvMyDG9abes3saB6dMimLOs+HMoQ== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.7.11.tgz#d7267a1ee9c4594fd3f7e37298818ec65687db63" + integrity sha512-vuGmgZjjp3zjcerQg+JA+tGOncOnJLWVkt8Aze5eWQLwTQGNgVLcyOTqgSCxWTR4J42ijHbBxnuRaL1Rv7XMdw== + dependencies: + "@xtuc/long" "4.2.1" + +"@webassemblyjs/utf8@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.7.11.tgz#06d7218ea9fdc94a6793aa92208160db3d26ee82" + integrity sha512-C6GFkc7aErQIAH+BMrIdVSmW+6HSe20wg57HEC1uqJP8E/xpMjXqQUxkQw07MhNDSDcGpxI9G5JSNOQCqJk4sA== + +"@webassemblyjs/wasm-edit@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.7.11.tgz#8c74ca474d4f951d01dbae9bd70814ee22a82005" + integrity sha512-FUd97guNGsCZQgeTPKdgxJhBXkUbMTY6hFPf2Y4OedXd48H97J+sOY2Ltaq6WGVpIH8o/TGOVNiVz/SbpEMJGg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/helper-wasm-section" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-opt" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + "@webassemblyjs/wast-printer" "1.7.11" + +"@webassemblyjs/wasm-gen@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.7.11.tgz#9bbba942f22375686a6fb759afcd7ac9c45da1a8" + integrity sha512-U/KDYp7fgAZX5KPfq4NOupK/BmhDc5Kjy2GIqstMhvvdJRcER/kUsMThpWeRP8BMn4LXaKhSTggIJPOeYHwISA== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wasm-opt@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.7.11.tgz#b331e8e7cef8f8e2f007d42c3a36a0580a7d6ca7" + integrity sha512-XynkOwQyiRidh0GLua7SkeHvAPXQV/RxsUeERILmAInZegApOUAIJfRuPYe2F7RcjOC9tW3Cb9juPvAC/sCqvg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-buffer" "1.7.11" + "@webassemblyjs/wasm-gen" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + +"@webassemblyjs/wasm-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.7.11.tgz#6e3d20fa6a3519f6b084ef9391ad58211efb0a1a" + integrity sha512-6lmXRTrrZjYD8Ng8xRyvyXQJYUQKYSXhJqXOBLw24rdiXsHAOlvw5PhesjdcaMadU/pyPQOJ5dHreMjBxwnQKg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-wasm-bytecode" "1.7.11" + "@webassemblyjs/ieee754" "1.7.11" + "@webassemblyjs/leb128" "1.7.11" + "@webassemblyjs/utf8" "1.7.11" + +"@webassemblyjs/wast-parser@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.7.11.tgz#25bd117562ca8c002720ff8116ef9072d9ca869c" + integrity sha512-lEyVCg2np15tS+dm7+JJTNhNWq9yTZvi3qEhAIIOaofcYlUp0UR5/tVqOwa/gXYr3gjwSZqw+/lS9dscyLelbQ== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/floating-point-hex-parser" "1.7.11" + "@webassemblyjs/helper-api-error" "1.7.11" + "@webassemblyjs/helper-code-frame" "1.7.11" + "@webassemblyjs/helper-fsm" "1.7.11" + "@xtuc/long" "4.2.1" + +"@webassemblyjs/wast-printer@1.7.11": + version "1.7.11" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.7.11.tgz#c4245b6de242cb50a2cc950174fdbf65c78d7813" + integrity sha512-m5vkAsuJ32QpkdkDOUPGSltrg8Cuk3KBx4YrmAGQwCZPRdUHXxG4phIOuuycLemHFr74sWL9Wthqss4fzdzSwg== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/wast-parser" "1.7.11" + "@xtuc/long" "4.2.1" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" + integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== + +abab@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" + integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-dynamic-import@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz#901ceee4c7faaef7e07ad2a47e890675da50a278" + integrity sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg== + dependencies: + acorn "^5.0.0" + +acorn-globals@^4.3.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + +acorn-jsx@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== + +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + +acorn@^5.0.0, acorn@^5.6.2: + version "5.7.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== + +acorn@^6.0.1, acorn@^6.0.2, acorn@^6.0.7: + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" + integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== + +ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5, ajv@^6.9.1: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +amd-name-resolver@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.2.0.tgz#fc41b3848824b557313897d71f8d5a0184fbe679" + integrity sha512-hlSTWGS1t6/xq5YCed7YALg7tKZL3rkl7UwEZ/eCIkn8JxmM6fU6Qs/1hwtjQqfuYxlffuUcgYEm0f5xP4YKaA== + dependencies: + ensure-posix-path "^1.0.1" + +amd-name-resolver@^1.2.1, amd-name-resolver@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/amd-name-resolver/-/amd-name-resolver-1.3.1.tgz#ffe71c683c6e7191fc4ae1bb3aaed15abea135d9" + integrity sha512-26qTEWqZQ+cxSYygZ4Cf8tsjDBLceJahhtewxtKZA3SRa4PluuqYCuheemDQD+7Mf5B7sr+zhTDWAHDh02a1Dw== + dependencies: + ensure-posix-path "^1.0.1" + object-hash "^1.3.1" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-escapes@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + dependencies: + type-fest "^0.11.0" + +ansi-html@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.0.0, ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +ansi-to-html@^0.6.6: + version "0.6.14" + resolved "https://registry.yarnpkg.com/ansi-to-html/-/ansi-to-html-0.6.14.tgz#65fe6d08bba5dd9db33f44a20aec331e0010dad8" + integrity sha512-7ZslfB1+EnFSDO5Ju+ue5Y6It19DRnZXWv8jrGHgIlPna5Mh4jz7BV5jCbQneXNFurQcKoolaaAjHtgSBfOIuA== + dependencies: + entities "^1.1.2" + +ansicolors@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.2.1.tgz#be089599097b74a5c9c4a84a0cdbcdb62bd87aef" + integrity sha1-vgiVmQl7dKXJxKhKDNvNtivYeu8= + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +aot-test-generators@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/aot-test-generators/-/aot-test-generators-0.1.0.tgz#43f0f615f97cb298d7919c1b0b4e6b7310b03cd0" + integrity sha1-Q/D2Ffl8spjXkZwbC05rcxCwPNA= + dependencies: + jsesc "^2.5.0" + +aproba@^1.0.3, aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-to-error@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-to-error/-/array-to-error-1.1.1.tgz#d68812926d14097a205579a667eeaf1856a44c07" + integrity sha1-1ogSkm0UCXogVXmmZ+6vGFakTAc= + dependencies: + array-to-sentence "^1.1.0" + +array-to-sentence@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc" + integrity sha1-yASVba+lMjJJWyBalFJ1OiWNOfw= + +array-union@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + +asn1.js@^4.0.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-never@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/assert-never/-/assert-never-1.2.0.tgz#e6597ed9e357f7e62c074dfa7c71e30ed7b67a8b" + integrity sha512-61QPxh2lfV5j2dBsEtwhz8/sUj+baAIuCpQxeWorGeMxlTkbeyGyq7igxJB8yij1JdzUhyoiekNHMXrMYnkjvA== + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +ast-types@0.13.3: + version "0.13.3" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.3.tgz#50da3f28d17bdbc7969a3a2d83a0e4a72ae755a7" + integrity sha512-XTZ7xGML849LkQP86sWdQzfhwbt3YwIO6MqbX9mUNYY98VKaaVZP7YNNm70IpwecbkkxmfC5IYAzOQ/2p29zRA== + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-disk-cache@^1.2.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/async-disk-cache/-/async-disk-cache-1.3.5.tgz#cc6206ed79bb6982b878fc52e0505e4f52b62a02" + integrity sha512-VZpqfR0R7CEOJZ/0FOTgWq70lCrZyS1rkI8PXugDUkTKyyAUgZ2zQ09gLhMkEn+wN8LYeUTPxZdXtlX/kmbXKQ== + dependencies: + debug "^2.1.3" + heimdalljs "^0.2.3" + istextorbinary "2.1.0" + mkdirp "^0.5.0" + rimraf "^2.5.3" + rsvp "^3.0.18" + username-sync "^1.0.2" + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async-promise-queue@^1.0.3, async-promise-queue@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/async-promise-queue/-/async-promise-queue-1.0.5.tgz#cb23bce9fce903a133946a700cc85f27f09ea49d" + integrity sha512-xi0aQ1rrjPWYmqbwr18rrSKbSaXIeIwSd1J4KAgVfkq8utNbdZoht7GfvfY6swFUAMJ9obkc4WPJmtGwl+B8dw== + dependencies: + async "^2.4.1" + debug "^2.6.8" + +async@^2.4.1, async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +async@~0.2.9: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.26.0, babel-core@^6.26.3: + version "6.26.3" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-eslint@^10.0.3: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ= + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340= + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo= + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk= + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI= + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo= + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI= + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-loader@^8.0.6: + version "8.1.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" + integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw== + dependencies: + find-cache-dir "^2.1.0" + loader-utils "^1.4.0" + mkdirp "^0.5.3" + pify "^4.0.1" + schema-utils "^2.6.5" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-debug-macros@^0.2.0, babel-plugin-debug-macros@^0.2.0-beta.6: + version "0.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.2.0.tgz#0120ac20ce06ccc57bf493b667cf24b85c28da7a" + integrity sha512-Wpmw4TbhR3Eq2t3W51eBAQSdKlr+uAyF0GI4GtPfMCD12Y4cIdpKC9l0RjNTH/P9isFypSqqewMPm7//fnZlNA== + dependencies: + semver "^5.3.0" + +babel-plugin-debug-macros@^0.3.0, babel-plugin-debug-macros@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-debug-macros/-/babel-plugin-debug-macros-0.3.3.tgz#29c3449d663f61c7385f5b8c72d8015b069a5cb7" + integrity sha512-E+NI8TKpxJDBbVkdWkwHrKgJi696mnRL8XYrOPYw82veNHPDORM9WIQifl6TpIo8PNy2tU2skPqbfkmHXrHKQA== + dependencies: + semver "^5.3.0" + +babel-plugin-dynamic-import-node@^2.3.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-ember-data-packages-polyfill@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-data-packages-polyfill/-/babel-plugin-ember-data-packages-polyfill-0.1.2.tgz#21154c095ddc703722b1fb8bb06c126c0b6d77dc" + integrity sha512-kTHnOwoOXfPXi00Z8yAgyD64+jdSXk3pknnS7NlqnCKAU6YDkXZ4Y7irl66kaZjZn0FBBt0P4YOZFZk85jYOww== + dependencies: + "@ember-data/rfc395-data" "^0.0.4" + +babel-plugin-ember-modules-api-polyfill@^2.12.0, babel-plugin-ember-modules-api-polyfill@^2.6.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/babel-plugin-ember-modules-api-polyfill/-/babel-plugin-ember-modules-api-polyfill-2.12.0.tgz#a5e703205ba4e625a7fab9bb1aea64ef3222cf75" + integrity sha512-ZQU4quX0TJ1yYyosPy5PFigKdCFEVHJ6H0b3hwjxekIP9CDwzk0OhQuKhCOPti+d52VWjjCjxu2BrXEih29mFw== + dependencies: + ember-rfc176-data "^0.3.12" + +babel-plugin-filter-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-filter-imports/-/babel-plugin-filter-imports-3.0.0.tgz#a849683837ad29960da17492fb32789ab6b09a11" + integrity sha512-p/chjzVTgCxUqyLM0q/pfWVZS7IJTwGQMwNg0LOvuQpKiTftQgZDtkGB8XvETnUw19rRcL7bJCTopSwibTN2tA== + dependencies: + "@babel/types" "^7.4.0" + lodash "^4.17.11" + +babel-plugin-htmlbars-inline-precompile@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-1.0.0.tgz#a9d2f6eaad8a3f3d361602de593a8cbef8179c22" + integrity sha512-4jvKEHR1bAX03hBDZ94IXsYCj3bwk9vYsn6ux6JZNL2U5pvzCWjqyrGahfsGNrhERyxw8IqcirOi9Q6WCo3dkQ== + +babel-plugin-htmlbars-inline-precompile@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-3.0.1.tgz#e1e38a4087f446578e419a21c112530c8df02345" + integrity sha512-ZiFY0nQjtdMPGIDwp/5LYOs6rCr54QfcSV5nPbrA7C++Fv4Vb2Q/qrKYx78t+dwmARJztnOBlObFk4z8veHxNA== + +babel-plugin-module-resolver@^3.1.1, babel-plugin-module-resolver@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz#ddfa5e301e3b9aa12d852a9979f18b37881ff5a7" + integrity sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA== + dependencies: + find-babel-config "^1.1.0" + glob "^7.1.2" + pkg-up "^2.0.0" + reselect "^3.0.1" + resolve "^1.4.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU= + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + integrity sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo= + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM= + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E= + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8= + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs= + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM= + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos= + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ= + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM= + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg= + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40= + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys= + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw= + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I= + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek= + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4= + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8= + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g= + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + integrity sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM= + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg== + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + integrity sha1-btAhFz4vy0htestFxgCahW9kcHE= + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +backbone@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.4.0.tgz#54db4de9df7c3811c3f032f34749a4cd27f3bd12" + integrity sha512-RLmDrRXkVdouTg38jcgHhyQ/2zjg7a8E6sz2zxfz21Hh17xDJYUHBZimVIt5fUyS8vbfpeSmTL3gUjTEvUV3qQ== + dependencies: + underscore ">=1.8.3" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64-js@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" + integrity sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q= + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base64id@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +basic-auth@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +"binaryextensions@1 || 2": + version "2.2.0" + resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-2.2.0.tgz#e7c6ba82d4f5f5758c26078fe8eea28881233311" + integrity sha512-bHhs98rj/7i/RZpCSJ3uk55pLXOItjIrh2sRQZSM6OoktScX+LxJzvlU+FELp9j3TdcddTmmYArLSGptCTwjuw== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +blank-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/blank-object/-/blank-object-1.0.2.tgz#f990793fbe9a8c8dd013fb3219420bec81d5f4b9" + integrity sha1-+ZB5P76ajI3QE/syGUIL7IHV9Lk= + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +bluebird@^3.1.1, bluebird@^3.4.6, bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +body@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= + dependencies: + continuable-cache "^0.3.1" + error "^7.0.0" + raw-body "~1.1.0" + safe-json-parse "~1.0.1" + +bops@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.3.tgz#c5cbf6fea8be7401ca5ea6d1679e6c4e8b407c79" + integrity sha1-xcv2/qi+dAHKXqbRZ55sTotAfHk= + dependencies: + base64-js "0.0.2" + to-utf8 "0.0.1" + +bower-config@^1.4.1: + version "1.4.3" + resolved "https://registry.yarnpkg.com/bower-config/-/bower-config-1.4.3.tgz#3454fecdc5f08e7aa9cc6d556e492be0669689ae" + integrity sha512-MVyyUk3d1S7d2cl6YISViwJBc2VXCkxF5AUFykvN0PQj5FsUiMNSgAYTso18oRFfyZ6XEtjrgg9MAaufHbOwNw== + dependencies: + graceful-fs "^4.1.3" + minimist "^0.2.1" + mout "^1.0.0" + osenv "^0.1.3" + untildify "^2.1.0" + wordwrap "^0.0.3" + +bower-endpoint-parser@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/bower-endpoint-parser/-/bower-endpoint-parser-0.2.2.tgz#00b565adbfab6f2d35addde977e97962acbcb3f6" + integrity sha1-ALVlrb+rby01rd3pd+l5Yqy8s/Y= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +broccoli-amd-funnel@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/broccoli-amd-funnel/-/broccoli-amd-funnel-2.0.1.tgz#dbdbfd28841731342d538126567c25bea3f15310" + integrity sha512-VRE+0PYAN4jQfkIq3GKRj4U/4UV9rVpLan5ll6fVYV4ziVg4OEfR5GUnILEg++QtR4xSaugRxCPU5XJLDy3bNQ== + dependencies: + broccoli-plugin "^1.3.0" + symlink-or-copy "^1.2.0" + +broccoli-asset-rev@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/broccoli-asset-rev/-/broccoli-asset-rev-3.0.0.tgz#65a28c8a062d6ee2cffd91ed2a8309e0f8253ac6" + integrity sha512-gAHQZnwvtl74tGevUqGuWoyOdJUdMMv0TjGSMzbdyGImr9fZcnM6xmggDA8bUawrMto9NFi00ZtNUgA4dQiUBw== + dependencies: + broccoli-asset-rewrite "^2.0.0" + broccoli-filter "^1.2.2" + broccoli-persistent-filter "^1.4.3" + json-stable-stringify "^1.0.0" + minimatch "^3.0.4" + rsvp "^3.0.6" + +broccoli-asset-rewrite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/broccoli-asset-rewrite/-/broccoli-asset-rewrite-2.0.0.tgz#603c4a52d4c8987a2f681254436923ac0a9c94ab" + integrity sha512-dqhxdQpooNi7LHe8J9Jdxp6o3YPFWl4vQmint6zrsn2sVbOo+wpyiX3erUSt0IBtjNkAxqJjuvS375o2cLBHTA== + dependencies: + broccoli-filter "^1.2.3" + +broccoli-babel-transpiler@^6.5.0: + version "6.5.1" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-6.5.1.tgz#a4afc8d3b59b441518eb9a07bd44149476e30738" + integrity sha512-w6GcnkxvHcNCte5FcLGEG1hUdQvlfvSN/6PtGWU/otg69Ugk8rUk51h41R0Ugoc+TNxyeFG1opRt2RlA87XzNw== + dependencies: + babel-core "^6.26.0" + broccoli-funnel "^2.0.1" + broccoli-merge-trees "^2.0.0" + broccoli-persistent-filter "^1.4.3" + clone "^2.0.0" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.7" + json-stable-stringify "^1.0.0" + rsvp "^4.8.2" + workerpool "^2.3.0" + +broccoli-babel-transpiler@^7.3.0, broccoli-babel-transpiler@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/broccoli-babel-transpiler/-/broccoli-babel-transpiler-7.4.0.tgz#f3069f0f77e8017aa17e1e757dfb4a30de044182" + integrity sha512-DzPXQr1C+zOgzXG40wqPjtjSSa6wRKb+Ls45Qtq7Pn+GxL3/jIvQOBZi0/irZ5dlYVbRMEZiUnaIBIOha2ygIw== + dependencies: + "@babel/core" "^7.8.3" + "@babel/polyfill" "^7.8.3" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.2" + broccoli-persistent-filter "^2.2.1" + clone "^2.1.2" + hash-for-dep "^1.4.7" + heimdalljs-logger "^0.1.9" + json-stable-stringify "^1.0.1" + rsvp "^4.8.4" + workerpool "^3.1.1" + +broccoli-builder@^0.18.14: + version "0.18.14" + resolved "https://registry.yarnpkg.com/broccoli-builder/-/broccoli-builder-0.18.14.tgz#4b79e2f844de11a4e1b816c3f49c6df4776c312d" + integrity sha1-S3ni+ETeEaThuBbD9Jxt9HdsMS0= + dependencies: + broccoli-node-info "^1.1.0" + heimdalljs "^0.2.0" + promise-map-series "^0.2.1" + quick-temp "^0.1.2" + rimraf "^2.2.8" + rsvp "^3.0.17" + silent-error "^1.0.1" + +broccoli-caching-writer@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-2.3.1.tgz#b93cf58f9264f003075868db05774f4e7f25bd07" + integrity sha1-uTz1j5Jk8AMHWGjbBXdPTn8lvQc= + dependencies: + broccoli-kitchen-sink-helpers "^0.2.5" + broccoli-plugin "1.1.0" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.2.5" + +broccoli-caching-writer@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/broccoli-caching-writer/-/broccoli-caching-writer-3.0.3.tgz#0bd2c96a9738d6a6ab590f07ba35c5157d7db476" + integrity sha1-C9LJapc41qarWQ8HujXFFX19tHY= + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.1" + debug "^2.1.1" + rimraf "^2.2.8" + rsvp "^3.0.17" + walk-sync "^0.3.0" + +broccoli-clean-css@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-clean-css/-/broccoli-clean-css-1.1.0.tgz#9db143d9af7e0ae79c26e3ac5a9bb2d720ea19fa" + integrity sha1-nbFD2a9+CuecJuOsWpuy1yDqGfo= + dependencies: + broccoli-persistent-filter "^1.1.6" + clean-css-promise "^0.1.0" + inline-source-map-comment "^1.0.5" + json-stable-stringify "^1.0.0" + +broccoli-concat@^3.2.2, broccoli-concat@^3.7.1, broccoli-concat@^3.7.4: + version "3.7.5" + resolved "https://registry.yarnpkg.com/broccoli-concat/-/broccoli-concat-3.7.5.tgz#223beda8c1184252cf08ae020a3d45ffa6a48218" + integrity sha512-rDs1Mej3Ej0Cy5yIO9oIQq5+BCv0opAwS2NW7M0BeCsAMeFM42Z/zacDUC6jKc5OV5wiHvGTyCPLnZkMe0h6kQ== + dependencies: + broccoli-debug "^0.6.5" + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.3.0" + ensure-posix-path "^1.0.2" + fast-sourcemap-concat "^1.4.0" + find-index "^1.1.0" + fs-extra "^4.0.3" + fs-tree-diff "^0.5.7" + lodash.merge "^4.6.2" + lodash.omit "^4.1.0" + lodash.uniq "^4.2.0" + walk-sync "^0.3.2" + +broccoli-config-loader@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/broccoli-config-loader/-/broccoli-config-loader-1.0.1.tgz#d10aaf8ebc0cb45c1da5baa82720e1d88d28c80a" + integrity sha512-MDKYQ50rxhn+g17DYdfzfEM9DjTuSGu42Db37A8TQHQe8geYEcUZ4SQqZRgzdAI3aRQNlA1yBHJfOeGmOjhLIg== + dependencies: + broccoli-caching-writer "^3.0.3" + +broccoli-config-replace@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/broccoli-config-replace/-/broccoli-config-replace-1.1.2.tgz#6ea879d92a5bad634d11329b51fc5f4aafda9c00" + integrity sha1-bqh52SpbrWNNETKbUfxfSq/anAA= + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.2.0" + debug "^2.2.0" + fs-extra "^0.24.0" + +broccoli-debug@^0.6.4, broccoli-debug@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/broccoli-debug/-/broccoli-debug-0.6.5.tgz#164a5cdafd8936e525e702bf8f91f39d758e2e78" + integrity sha512-RIVjHvNar9EMCLDW/FggxFRXqpjhncM/3qq87bn/y+/zR9tqEkHvTqbyOc4QnB97NO2m6342w4wGkemkaeOuWg== + dependencies: + broccoli-plugin "^1.2.1" + fs-tree-diff "^0.5.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + symlink-or-copy "^1.1.8" + tree-sync "^1.2.2" + +broccoli-file-creator@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/broccoli-file-creator/-/broccoli-file-creator-2.1.1.tgz#7351dd2496c762cfce7736ce9b49e3fce0c7b7db" + integrity sha512-YpjOExWr92C5vhnK0kmD81kM7U09kdIRZk9w4ZDCDHuHXW+VE/x6AGEOQQW3loBQQ6Jk+k+TSm8dESy4uZsnjw== + dependencies: + broccoli-plugin "^1.1.0" + mkdirp "^0.5.1" + +broccoli-filter@^1.2.2, broccoli-filter@^1.2.3: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-filter/-/broccoli-filter-1.3.0.tgz#71e3a8e32a17f309e12261919c5b1006d6766de6" + integrity sha512-VXJXw7eBfG82CFxaBDjYmyN7V72D4In2zwLVQJd/h3mBfF3CMdRTsv2L20lmRTtCv1sAHcB+LgMso90e/KYiLw== + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + broccoli-plugin "^1.0.0" + copy-dereference "^1.0.0" + debug "^2.2.0" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rsvp "^3.0.18" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + +broccoli-funnel-reducer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/broccoli-funnel-reducer/-/broccoli-funnel-reducer-1.0.0.tgz#11365b2a785aec9b17972a36df87eef24c5cc0ea" + integrity sha1-ETZbKnha7JsXlyo234fu8kxcwOo= + +broccoli-funnel@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-1.2.0.tgz#cddc3afc5ff1685a8023488fff74ce6fb5a51296" + integrity sha1-zdw6/F/xaFqAI0iP/3TOb7WlEpY= + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + exists-sync "0.0.4" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^0.3.1" + +broccoli-funnel@^2.0.0, broccoli-funnel@^2.0.1, broccoli-funnel@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/broccoli-funnel/-/broccoli-funnel-2.0.2.tgz#0edf629569bc10bd02cc525f74b9a38e71366a75" + integrity sha512-/vDTqtv7ipjEZQOVqO4vGDVAOZyuYzQ/EgGoyewfOgh1M7IQAToBKZI0oAQPgMBeFPPlIbfMuAngk+ohPBuaHQ== + dependencies: + array-equal "^1.0.0" + blank-object "^1.0.1" + broccoli-plugin "^1.3.0" + debug "^2.2.0" + fast-ordered-set "^1.0.0" + fs-tree-diff "^0.5.3" + heimdalljs "^0.2.0" + minimatch "^3.0.0" + mkdirp "^0.5.0" + path-posix "^1.0.0" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + walk-sync "^0.3.1" + +broccoli-kitchen-sink-helpers@^0.2.5: + version "0.2.9" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.2.9.tgz#a5e0986ed8d76fb5984b68c3f0450d3a96e36ecc" + integrity sha1-peCYbtjXb7WYS2jD8EUNOpbjbsw= + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + +broccoli-kitchen-sink-helpers@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/broccoli-kitchen-sink-helpers/-/broccoli-kitchen-sink-helpers-0.3.1.tgz#77c7c18194b9664163ec4fcee2793444926e0c06" + integrity sha1-d8fBgZS5ZkFj7E/O4nk0RJJuDAY= + dependencies: + glob "^5.0.10" + mkdirp "^0.5.1" + +broccoli-lint-eslint@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/broccoli-lint-eslint/-/broccoli-lint-eslint-5.0.0.tgz#05365879d597dd78496a1c718db0e5ea5d4a2bde" + integrity sha512-V7M6U4th21bf1X4u3KoZa0xkcPq9JCSyKxB/nCWCBFMI3rkrB8nlyDLd8DKIUTqL+ojlFOGV5lohPZwndw0sZw== + dependencies: + aot-test-generators "^0.1.0" + broccoli-concat "^3.2.2" + broccoli-persistent-filter "^2.1.0" + eslint "^5.6.0" + json-stable-stringify "^1.0.1" + lodash.defaultsdeep "^4.6.0" + md5-hex "^2.0.0" + +broccoli-merge-trees@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-1.2.4.tgz#a001519bb5067f06589d91afa2942445a2d0fdb5" + integrity sha1-oAFRm7UGfwZYnZGvopQkRaLQ/bU= + dependencies: + broccoli-plugin "^1.3.0" + can-symlink "^1.0.0" + fast-ordered-set "^1.0.2" + fs-tree-diff "^0.5.4" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + +broccoli-merge-trees@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-2.0.1.tgz#14d4b7fc1a90318c12b16f843e6ba2693808100c" + integrity sha512-WjaexJ+I8BxP5V5RNn6um/qDRSmKoiBC/QkRi79FT9ClHfldxRyCDs9mcV7mmoaPlsshmmPaUz5jdtcKA6DClQ== + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^1.0.1" + +broccoli-merge-trees@^3.0.0, broccoli-merge-trees@^3.0.1, broccoli-merge-trees@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/broccoli-merge-trees/-/broccoli-merge-trees-3.0.2.tgz#f33b451994225522b5c9bcf27d59decfd8ba537d" + integrity sha512-ZyPAwrOdlCddduFbsMyyFzJUrvW6b04pMvDiAQZrCwghlvgowJDY+EfoXn+eR1RRA5nmGHJ+B68T63VnpRiT1A== + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^2.0.0" + +broccoli-middleware@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/broccoli-middleware/-/broccoli-middleware-2.1.1.tgz#183635bbef4dc1241533ee001a162f013d776cb9" + integrity sha512-BK8aPhQpOLsHWiftrqXQr84XsvzUqeaN4PlCQOYg5yM0M+WKAHtX2WFXmicSQZOVgKDyh5aeoNTFkHjBAEBzwQ== + dependencies: + ansi-html "^0.0.7" + handlebars "^4.0.4" + has-ansi "^3.0.0" + mime-types "^2.1.18" + +broccoli-module-normalizer@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/broccoli-module-normalizer/-/broccoli-module-normalizer-1.3.0.tgz#f9982d9cbb776b4ed754161cc6547784d3eb19de" + integrity sha512-0idZCOtdVG6xXoQ36Psc1ApMCr3lW5DB+WEAOEwHcUoESIBHzwcRPQTxheGIjZ5o0hxpsRYAUH5x0ErtNezbrQ== + dependencies: + broccoli-plugin "^1.3.0" + merge-trees "^1.0.1" + rimraf "^2.6.2" + symlink-or-copy "^1.1.8" + +broccoli-module-unification-reexporter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/broccoli-module-unification-reexporter/-/broccoli-module-unification-reexporter-1.0.0.tgz#031909c5d3f159ec11d5f9e2346f2861db8acb3e" + integrity sha512-HTi9ua520M20aBZomaiBopsSt3yjL7J/paR3XPjieygK7+ShATBiZdn0B+ZPiniBi4I8JuMn1q0fNFUevtP//A== + dependencies: + broccoli-plugin "^1.3.0" + mkdirp "^0.5.1" + walk-sync "^0.3.2" + +broccoli-node-api@^1.6.0, broccoli-node-api@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/broccoli-node-api/-/broccoli-node-api-1.7.0.tgz#391aa6edecd2a42c63c111b4162956b2fa288cb6" + integrity sha512-QIqLSVJWJUVOhclmkmypJJH9u9s/aWH4+FH6Q6Ju5l+Io4dtwqdPUNmDfw40o6sxhbZHhqGujDJuHTML1wG8Yw== + +broccoli-node-info@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-1.1.0.tgz#3aa2e31e07e5bdb516dd25214f7c45ba1c459412" + integrity sha1-OqLjHgflvbUW3SUhT3xFuhxFlBI= + +broccoli-node-info@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/broccoli-node-info/-/broccoli-node-info-2.1.0.tgz#ca84560e8570ff78565bea1699866ddbf58ad644" + integrity sha512-l6qDuboJThHfRVVWQVaTs++bFdrFTP0gJXgsWenczc1PavRVUmL1Eyb2swTAXXMpDOnr2zhNOBLx4w9AxkqbPQ== + +broccoli-output-wrapper@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/broccoli-output-wrapper/-/broccoli-output-wrapper-2.0.0.tgz#f1e0b9b2f259a67fd41a380141c3c20b096828e6" + integrity sha512-V/ozejo+snzNf75i/a6iTmp71k+rlvqjE3+jYfimuMwR1tjNNRdtfno+NGNQB2An9bIAeqZnKhMDurAznHAdtA== + dependencies: + heimdalljs-logger "^0.1.10" + +broccoli-persistent-filter@^1.1.6, broccoli-persistent-filter@^1.4.3: + version "1.4.6" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-1.4.6.tgz#80762d19000880a77da33c34373299c0f6a3e615" + integrity sha512-0RejLwoC95kv4kta8KAa+FmECJCK78Qgm8SRDEK7YyU0N9Cx6KpY3UCDy9WELl3mCXLN8TokNxc7/hp3lL4lfw== + dependencies: + async-disk-cache "^1.2.1" + async-promise-queue "^1.0.3" + broccoli-plugin "^1.0.0" + fs-tree-diff "^0.5.2" + hash-for-dep "^1.0.2" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rimraf "^2.6.1" + rsvp "^3.0.18" + symlink-or-copy "^1.0.1" + walk-sync "^0.3.1" + +broccoli-persistent-filter@^2.1.0, broccoli-persistent-filter@^2.2.1, broccoli-persistent-filter@^2.2.2, broccoli-persistent-filter@^2.3.0, broccoli-persistent-filter@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/broccoli-persistent-filter/-/broccoli-persistent-filter-2.3.1.tgz#4a052e0e0868b344c3a2977e35a3d497aa9eca72" + integrity sha512-hVsmIgCDrl2NFM+3Gs4Cr2TA6UPaIZip99hN8mtkaUPgM8UeVnCbxelCvBjUBHo0oaaqP5jzqqnRVvb568Yu5g== + dependencies: + async-disk-cache "^1.2.1" + async-promise-queue "^1.0.3" + broccoli-plugin "^1.0.0" + fs-tree-diff "^2.0.0" + hash-for-dep "^1.5.0" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + mkdirp "^0.5.1" + promise-map-series "^0.2.1" + rimraf "^2.6.1" + rsvp "^4.7.0" + symlink-or-copy "^1.0.1" + sync-disk-cache "^1.3.3" + walk-sync "^1.0.0" + +broccoli-plugin@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.1.0.tgz#73e2cfa05f8ea1e3fc1420c40c3d9e7dc724bf02" + integrity sha1-c+LPoF+OoeP8FCDEDD2efcckvwI= + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.0.1" + +broccoli-plugin@^1.0.0, broccoli-plugin@^1.1.0, broccoli-plugin@^1.2.0, broccoli-plugin@^1.2.1, broccoli-plugin@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz#a26315732fb99ed2d9fb58f12a1e14e986b4fabd" + integrity sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ== + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + +broccoli-plugin@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-2.1.0.tgz#2fab6c578219cfcc64f773e9616073313fc8b334" + integrity sha512-ElE4caljW4slapyEhSD9jU9Uayc8SoSABWdmY9SqbV8DHNxU6xg1jJsPcMm+cXOvggR3+G+OXAYQeFjWVnznaw== + dependencies: + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + +broccoli-plugin@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz#54ba6dd90a42ec3db5624063292610e326b1e542" + integrity sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA== + dependencies: + broccoli-node-api "^1.6.0" + broccoli-output-wrapper "^2.0.0" + fs-merger "^3.0.1" + promise-map-series "^0.2.1" + quick-temp "^0.1.3" + rimraf "^2.3.4" + symlink-or-copy "^1.1.8" + +broccoli-slow-trees@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/broccoli-slow-trees/-/broccoli-slow-trees-3.1.0.tgz#8e48903f59e061bf1213963733b9e61dec2ee5d7" + integrity sha512-FRI7mRTk2wjIDrdNJd6znS7Kmmne4VkAkl8Ix1R/VoePFMD0g0tEl671xswzFqaRjpT9Qu+CC4hdXDLDJBuzMw== + dependencies: + heimdalljs "^0.2.1" + +broccoli-source@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-1.1.0.tgz#54f0e82c8b73f46580cbbc4f578f0b32fca8f809" + integrity sha1-VPDoLItz9GWAy7xPV48LMvyo+Ak= + +broccoli-source@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/broccoli-source/-/broccoli-source-3.0.0.tgz#c7c9ba24505941b72a0244568285bc859f69dfbd" + integrity sha512-G4Zc8HngZIdASyQOiz/9H/0Gjc2F02EFwhWF4wiueaI+/FBrM9Ixj6Prno/1aiLIYcN0JvRC3oytN9uOVonTww== + dependencies: + broccoli-node-api "^1.6.0" + +broccoli-sri-hash@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/broccoli-sri-hash/-/broccoli-sri-hash-2.1.2.tgz#bc69905ed7a381ad325cc0d02ded071328ebf3f3" + integrity sha1-vGmQXtejga0yXMDQLe0HEyjr8/M= + dependencies: + broccoli-caching-writer "^2.2.0" + mkdirp "^0.5.1" + rsvp "^3.1.0" + sri-toolbox "^0.2.0" + symlink-or-copy "^1.0.1" + +broccoli-stew@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/broccoli-stew/-/broccoli-stew-3.0.0.tgz#fd1d19d162ad9490b42e5c563b78c26eb1e80b95" + integrity sha512-NXfi+Vas24n3Ivo21GvENTI55qxKu7OwKRnCLWXld8MiLiQKQlWIq28eoARaFj0lTUFwUa4jKZeA7fW9PiWQeg== + dependencies: + broccoli-debug "^0.6.5" + broccoli-funnel "^2.0.0" + broccoli-merge-trees "^3.0.1" + broccoli-persistent-filter "^2.3.0" + broccoli-plugin "^2.1.0" + chalk "^2.4.1" + debug "^4.1.1" + ensure-posix-path "^1.0.1" + fs-extra "^8.0.1" + minimatch "^3.0.4" + resolve "^1.11.1" + rsvp "^4.8.5" + symlink-or-copy "^1.2.0" + walk-sync "^1.1.3" + +broccoli-uglify-sourcemap@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/broccoli-uglify-sourcemap/-/broccoli-uglify-sourcemap-3.2.0.tgz#d96f1d41f6c18e9a5d49af1a5ab9489cdcac1c6c" + integrity sha512-kkkn8v7kXdWwnZNekq+3ILuTAGkZoaoEMUYCKoER5/uokuoyTjtdYLHaE7UxHkuPEuLfjvJYv21sCCePZ74/2g== + dependencies: + async-promise-queue "^1.0.5" + broccoli-plugin "^1.2.1" + debug "^4.1.0" + lodash.defaultsdeep "^4.6.1" + matcher-collection "^2.0.0" + mkdirp "^0.5.0" + source-map-url "^0.4.0" + symlink-or-copy "^1.0.1" + terser "^4.3.9" + walk-sync "^1.1.3" + workerpool "^5.0.1" + +broccoli@^3.2.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/broccoli/-/broccoli-3.4.1.tgz#3acf2c8d998ed57fb7a89dee1b1b5e8e956e285b" + integrity sha512-DTIHD4olRsXr+Y+6k/E6PqnnSKAAROwgM77qmCloojmJS19QiIAJq7Pq2w6qZx9tQZt1zByhYgLm3r1m73yTPQ== + dependencies: + "@types/chai" "^4.2.9" + "@types/chai-as-promised" "^7.1.2" + "@types/express" "^4.17.2" + ansi-html "^0.0.7" + broccoli-node-info "^2.1.0" + broccoli-slow-trees "^3.0.1" + broccoli-source "^3.0.0" + commander "^4.1.1" + connect "^3.6.6" + console-ui "^3.0.4" + esm "^3.2.4" + findup-sync "^4.0.0" + handlebars "^4.7.3" + heimdalljs "^0.2.6" + heimdalljs-logger "^0.1.9" + https "^1.0.0" + mime-types "^2.1.26" + resolve-path "^1.4.0" + rimraf "^3.0.2" + sane "^4.0.0" + tmp "^0.0.33" + tree-sync "^2.0.0" + underscore.string "^3.2.2" + watch-detector "^1.0.0" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ== + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +browserslist@^4.8.5, browserslist@^4.9.1: + version "4.12.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d" + integrity sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg== + dependencies: + caniuse-lite "^1.0.30001043" + electron-to-chromium "^1.3.413" + node-releases "^1.1.53" + pkg-up "^2.0.0" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +builtins@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= + +bytes@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cacache@^12.0.2: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + +calculate-cache-key-for-tree@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/calculate-cache-key-for-tree/-/calculate-cache-key-for-tree-2.0.0.tgz#7ac57f149a4188eacb0a45b210689215d3fef8d6" + integrity sha512-Quw8a6y8CPmRd6eU+mwypktYCwUcf8yVFIRbNZ6tPQEckX9yd+EBVEPC/GSZZrMWH9e7Vz4pT7XhpmyApRByLQ== + dependencies: + json-stable-stringify "^1.0.1" + +call-me-maybe@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" + integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +can-symlink@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/can-symlink/-/can-symlink-1.0.0.tgz#97b607d8a84bb6c6e228b902d864ecb594b9d219" + integrity sha1-l7YH2KhLtsbiKLkC2GTstZS50hk= + dependencies: + tmp "0.0.28" + +caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001043: + version "1.0.30001048" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001048.tgz#4bb4f1bc2eb304e5e1154da80b93dee3f1cf447e" + integrity sha512-g1iSHKVxornw0K8LG9LLdf+Fxnv7T1Z+mMsf0/YYLclQX4Cd522Ap0Lrw6NFqHgezit78dtyWxzlV2Xfc7vgRg== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +capture-stack-trace@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" + integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== + +cardinal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-1.0.0.tgz#50e21c1b0aa37729f9377def196b5a9cec932ee9" + integrity sha1-UOIcGwqjdyn5N33vGWtanOyTLuk= + dependencies: + ansicolors "~0.2.1" + redeyed "~1.0.0" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.0.0, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +charm@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/charm/-/charm-1.0.2.tgz#8add367153a6d9a581331052c4090991da995e35" + integrity sha1-it02cVOm2aWBMxBSxAkJkdqZXjU= + dependencies: + inherits "^2.0.1" + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chrome-trace-event@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== + dependencies: + tslib "^1.9.0" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-base-url@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-base-url/-/clean-base-url-1.0.0.tgz#c901cf0a20b972435b0eccd52d056824a4351b7b" + integrity sha1-yQHPCiC5ckNbDszVLQVoJKQ1G3s= + +clean-css-promise@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/clean-css-promise/-/clean-css-promise-0.1.1.tgz#43f3d2c8dfcb2bf071481252cd9b76433c08eecb" + integrity sha1-Q/PSyN/LK/BxSBJSzZt2QzwI7ss= + dependencies: + array-to-error "^1.0.0" + clean-css "^3.4.5" + pinkie-promise "^2.0.0" + +clean-css@^3.4.5: + version "3.4.28" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff" + integrity sha1-vxlF6C/ICPVWlebd6uwBQA79A/8= + dependencies: + commander "2.8.x" + source-map "0.4.x" + +clean-up-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clean-up-path/-/clean-up-path-1.0.0.tgz#de9e8196519912e749c9eaf67c13d64fac72a3e5" + integrity sha512-PHGlEF0Z6976qQyN6gM7kKH6EH0RdfZcc8V+QhFe36eRxV0SMH5OUBZG7Bxa9YcreNzyNbK63cGiZxdSZgosRw== + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= + dependencies: + restore-cursor "^2.0.0" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.3.0.tgz#0632239a4b5aa4c958610142c34bb7a651fc8df5" + integrity sha512-Xs2Hf2nzrvJMFKimOR7YR0QwZ8fc0u98kdtwN1eNAZzNQgH3vK2pXzff6GJtKh7S5hoJ87ECiAiZFS2fb5Ii2w== + +cli-table3@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cli-table@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" + integrity sha1-9TsFJmqLGguTSz0IIebi3FkUriM= + dependencies: + colors "1.0.3" + +cli-width@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +clone@^2.0.0, clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + +colors@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@2.12.2: + version "2.12.2" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.12.2.tgz#0f5946c427ed9ec0d91a46bb9def53e54650e555" + integrity sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA== + +commander@2.8.x: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= + dependencies: + graceful-readlink ">= 1.0.0" + +commander@^2.20.0, commander@^2.6.0, commander@~2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +common-tags@^1.4.0, common-tags@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" + integrity sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +connect@^3.6.6: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +console-ui@^3.0.4, console-ui@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/console-ui/-/console-ui-3.1.1.tgz#681a0414e8b0a23ed679d0a2802e39d920801171" + integrity sha512-22y+uk4AGq9quz6kofKQjkeCIAm86+MTxT/RZMFm8fMArP2lAkzxjUjNyrw7S6wXnnB+qRnC+/2ANMTke68RTQ== + dependencies: + chalk "^2.1.0" + inquirer "^6" + json-stable-stringify "^1.0.1" + ora "^3.4.0" + through2 "^3.0.1" + +consolidate@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7" + integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw== + dependencies: + bluebird "^3.1.1" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +continuable-cache@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= + +convert-source-map@^1.5.1, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-dereference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/copy-dereference/-/copy-dereference-1.0.0.tgz#6b131865420fd81b413ba994b44d3655311152b6" + integrity sha1-axMYZUIP2BtBO6mUtE02VTERUrY= + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.6.2: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" + integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== + dependencies: + browserslist "^4.8.5" + semver "7.0.0" + +core-js@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + integrity sha1-TekR5mew6ukSTjQlS1OupvxhjT4= + +core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.5: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-object@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/core-object/-/core-object-3.1.5.tgz#fa627b87502adc98045e44678e9a8ec3b9c0d2a9" + integrity sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg== + dependencies: + chalk "^2.0.0" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +create-ecdh@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-error-class@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" + integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= + dependencies: + capture-stack-trace "^1.0.0" + +create-hash@^1.1.0, create-hash@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.0: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.2.tgz#d0d7dcfa74e89115c7619f4f721a94e1fdb716d6" + integrity sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +cssom@0.3.x, cssom@^0.3.4: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +dag-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dag-map/-/dag-map-2.0.2.tgz#9714b472de82a1843de2fba9b6876938cab44c68" + integrity sha1-lxS0ct6CoYQ94vuptodpOMq0TGg= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + +debug@2.6.9, debug@^2.1.0, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.0.0, debug@^3.0.1, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-properties@^1.1.2, define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg= + dependencies: + repeating "^2.0.0" + +detect-indent@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" + integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== + +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-newline@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" + integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== + dependencies: + path-type "^3.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + +dot-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" + integrity sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + +duplex@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/duplex/-/duplex-1.0.0.tgz#6abc5c16ec17e4c578578727126700590d3a2dda" + integrity sha1-arxcFuwX5MV4V4cnEmcAWQ06Ldo= + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +editions@^1.1.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.413, electron-to-chromium@^1.3.47: + version "1.3.421" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.421.tgz#4abfe7e49070b5b437ec2ce442543add8eb66800" + integrity sha512-ogxgmvHGfDuLA+GtgfK0jkFWlBb4MCZK2U1MM+l98sf4U3Ixtrfw1iC9w4mQqNvo+lHgM4pR62TqoT4QrvKJCw== + +elliptic@^6.0.0: + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +ember-assign-polyfill@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/ember-assign-polyfill/-/ember-assign-polyfill-2.6.0.tgz#07847e3357ee35b33f886a0b5fbec6873f6860eb" + integrity sha512-Y8NzOmHI/g4PuJ+xC14eTYiQbigNYddyHB8FY2kuQMxThTEIDE7SJtgttJrYYcPciOu0Tnb5ff36iO46LeiXkw== + dependencies: + ember-cli-babel "^6.16.0" + ember-cli-version-checker "^2.0.0" + +ember-auto-import@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/ember-auto-import/-/ember-auto-import-1.5.3.tgz#b32936f874d1ed7057ad2ed3f6116357820be44b" + integrity sha512-7JfdunM1BmLy/lyUXu7uEoi0Gi4+dxkGM23FgIEyW5g7z4MidhP53Fc61t49oPSnq7+J4lLpbH1f6C+mDMgb4A== + dependencies: + "@babel/core" "^7.1.6" + "@babel/preset-env" "^7.0.0" + "@babel/traverse" "^7.1.6" + "@babel/types" "^7.1.6" + "@embroider/core" "^0.4.3" + babel-core "^6.26.3" + babel-loader "^8.0.6" + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-template "^6.26.0" + babylon "^6.18.0" + broccoli-debug "^0.6.4" + broccoli-plugin "^1.3.0" + debug "^3.1.0" + ember-cli-babel "^6.6.0" + enhanced-resolve "^4.0.0" + fs-extra "^6.0.1" + fs-tree-diff "^1.0.0" + handlebars "^4.3.1" + js-string-escape "^1.0.1" + lodash "^4.17.10" + mkdirp "^0.5.1" + pkg-up "^2.0.0" + resolve "^1.7.1" + rimraf "^2.6.2" + symlink-or-copy "^1.2.0" + typescript-memoize "^1.0.0-alpha.3" + walk-sync "^0.3.3" + webpack "~4.28" + +ember-cli-babel-plugin-helpers@^1.0.0, ember-cli-babel-plugin-helpers@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel-plugin-helpers/-/ember-cli-babel-plugin-helpers-1.1.0.tgz#de3baedd093163b6c2461f95964888c1676325ac" + integrity sha512-Zr4my8Xn+CzO0gIuFNXji0eTRml5AxZUTDQz/wsNJ5AJAtyFWCY4QtKdoELNNbiCVGt1lq5yLiwTm4scGKu6xA== + +ember-cli-babel@^6.0.0-beta.4, ember-cli-babel@^6.16.0, ember-cli-babel@^6.6.0, ember-cli-babel@^6.8.1: + version "6.18.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz#3f6435fd275172edeff2b634ee7b29ce74318957" + integrity sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA== + dependencies: + amd-name-resolver "1.2.0" + babel-plugin-debug-macros "^0.2.0-beta.6" + babel-plugin-ember-modules-api-polyfill "^2.6.0" + babel-plugin-transform-es2015-modules-amd "^6.24.0" + babel-polyfill "^6.26.0" + babel-preset-env "^1.7.0" + broccoli-babel-transpiler "^6.5.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.0" + broccoli-source "^1.1.0" + clone "^2.0.0" + ember-cli-version-checker "^2.1.2" + semver "^5.5.0" + +ember-cli-babel@^7.11.0, ember-cli-babel@^7.12.0, ember-cli-babel@^7.13.0, ember-cli-babel@^7.13.2, ember-cli-babel@^7.7.3: + version "7.19.0" + resolved "https://registry.yarnpkg.com/ember-cli-babel/-/ember-cli-babel-7.19.0.tgz#e6eddea18a867231fcf90a80689e92b98be9a63b" + integrity sha512-HiWKuoyy35vGEr+iCw6gUnQ3pS5qslyTlKEDW8cVoMbvZNGYBgRxHed5nklVUh+BS74AwR9lsp25BTAagYAP9Q== + dependencies: + "@babel/core" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/plugin-proposal-class-properties" "^7.8.3" + "@babel/plugin-proposal-decorators" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-runtime" "^7.9.0" + "@babel/plugin-transform-typescript" "^7.9.0" + "@babel/polyfill" "^7.8.7" + "@babel/preset-env" "^7.9.0" + "@babel/runtime" "^7.9.0" + amd-name-resolver "^1.2.1" + babel-plugin-debug-macros "^0.3.0" + babel-plugin-ember-data-packages-polyfill "^0.1.2" + babel-plugin-ember-modules-api-polyfill "^2.12.0" + babel-plugin-module-resolver "^3.1.1" + broccoli-babel-transpiler "^7.4.0" + broccoli-debug "^0.6.4" + broccoli-funnel "^2.0.1" + broccoli-source "^1.1.0" + clone "^2.1.2" + ember-cli-babel-plugin-helpers "^1.1.0" + ember-cli-version-checker "^4.1.0" + ensure-posix-path "^1.0.2" + fixturify-project "^1.10.0" + rimraf "^3.0.1" + semver "^5.5.0" + +ember-cli-dependency-checker@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-dependency-checker/-/ember-cli-dependency-checker-3.2.0.tgz#9202ad9e14d6fda33cffc22a11c343c2a8885330" + integrity sha512-dkSmcJ/jY/2ms/S6ph2jXSfOW5VfOpLfg5DFEbra0SaMNgYkNDFF1o0U4OdTsG37L5h/AXWNuVtnOa4TMabz9Q== + dependencies: + chalk "^2.3.0" + find-yarn-workspace-root "^1.1.0" + is-git-url "^1.0.0" + resolve "^1.5.0" + semver "^5.3.0" + +ember-cli-eslint@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-eslint/-/ember-cli-eslint-5.1.0.tgz#acdb9b072911e04b07c313b610f514db4086d21a" + integrity sha512-o6787b0tgkRNp+KJo5BiQxtkLuz/yyYqVWF31LPrh+ZCC8jETrfyjsuk8VPDxKLGq7qEiQNJUgOEW87HTad7Vg== + dependencies: + broccoli-lint-eslint "^5.0.0" + ember-cli-version-checker "^3.0.0" + rsvp "^4.6.1" + walk-sync "^1.0.0" + +ember-cli-get-component-path-option@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-get-component-path-option/-/ember-cli-get-component-path-option-1.0.0.tgz#0d7b595559e2f9050abed804f1d8eff1b08bc771" + integrity sha1-DXtZVVni+QUKvtgE8djv8bCLx3E= + +ember-cli-htmlbars-inline-precompile@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars-inline-precompile/-/ember-cli-htmlbars-inline-precompile-2.1.0.tgz#61b91ff1879d44ae504cadb46fb1f2604995ae08" + integrity sha512-BylIHduwQkncPhnj0ZyorBuljXbTzLgRo6kuHf1W+IHFxThFl2xG+r87BVwsqx4Mn9MTgW9SE0XWjwBJcSWd6Q== + dependencies: + babel-plugin-htmlbars-inline-precompile "^1.0.0" + ember-cli-version-checker "^2.1.2" + hash-for-dep "^1.2.3" + heimdalljs-logger "^0.1.9" + silent-error "^1.1.0" + +ember-cli-htmlbars@^4.2.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ember-cli-htmlbars/-/ember-cli-htmlbars-4.3.1.tgz#4af8adc21ab3c4953f768956b7f7d207782cb175" + integrity sha512-CW6AY/yzjeVqoRtItOKj3hcYzc5dWPRETmeCzr2Iqjt5vxiVtpl0z5VTqHqIlT5fsFx6sGWBQXNHIe+ivYsxXQ== + dependencies: + "@ember/edition-utils" "^1.2.0" + babel-plugin-htmlbars-inline-precompile "^3.0.1" + broccoli-debug "^0.6.5" + broccoli-persistent-filter "^2.3.1" + broccoli-plugin "^3.1.0" + common-tags "^1.8.0" + ember-cli-babel-plugin-helpers "^1.1.0" + fs-tree-diff "^2.0.1" + hash-for-dep "^1.5.1" + heimdalljs-logger "^0.1.10" + json-stable-stringify "^1.0.1" + semver "^6.3.0" + strip-bom "^4.0.0" + walk-sync "^2.0.2" + +ember-cli-inject-live-reload@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ember-cli-inject-live-reload/-/ember-cli-inject-live-reload-2.0.2.tgz#95edb543b386239d35959e5ea9579f5382976ac7" + integrity sha512-HDD6o/kBHT/kUtazklU0OW23q2jigIN42QmcpFdXUSvJ2/2SYA6yIqSUxWfJgISmtn5gTNZ2KPq1p3dLkhJxSQ== + dependencies: + clean-base-url "^1.0.0" + ember-cli-version-checker "^3.1.3" + +ember-cli-is-package-missing@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-is-package-missing/-/ember-cli-is-package-missing-1.0.0.tgz#6e6184cafb92635dd93ca6c946b104292d4e3390" + integrity sha1-bmGEyvuSY13ZPKbJRrEEKS1OM5A= + +ember-cli-lodash-subset@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ember-cli-lodash-subset/-/ember-cli-lodash-subset-2.0.1.tgz#20cb68a790fe0fde2488ddfd8efbb7df6fe766f2" + integrity sha1-IMtop5D+D94kiN39jvu332/nZvI= + +ember-cli-normalize-entity-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-normalize-entity-name/-/ember-cli-normalize-entity-name-1.0.0.tgz#0b14f7bcbc599aa117b5fddc81e4fd03c4bad5b7" + integrity sha1-CxT3vLxZmqEXtf3cgeT9A8S61bc= + dependencies: + silent-error "^1.0.0" + +ember-cli-path-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-path-utils/-/ember-cli-path-utils-1.0.0.tgz#4e39af8b55301cddc5017739b77a804fba2071ed" + integrity sha1-Tjmvi1UwHN3FAXc5t3qAT7ogce0= + +ember-cli-preprocess-registry@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ember-cli-preprocess-registry/-/ember-cli-preprocess-registry-3.3.0.tgz#685837a314fbe57224bd54b189f4b9c23907a2de" + integrity sha512-60GYpw7VPeB7TvzTLZTuLTlHdOXvayxjAQ+IxM2T04Xkfyu75O2ItbWlftQW7NZVGkaCsXSRAmn22PG03VpLMA== + dependencies: + broccoli-clean-css "^1.1.0" + broccoli-funnel "^2.0.1" + debug "^3.0.1" + process-relative-require "^1.0.0" + +ember-cli-sri@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ember-cli-sri/-/ember-cli-sri-2.1.1.tgz#971620934a4b9183cf7923cc03e178b83aa907fd" + integrity sha1-lxYgk0pLkYPPeSPMA+F4uDqpB/0= + dependencies: + broccoli-sri-hash "^2.1.0" + +ember-cli-string-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz#39b677fc2805f55173735376fcef278eaa4452a1" + integrity sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE= + +ember-cli-template-lint@^1.0.0-beta.3: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-template-lint/-/ember-cli-template-lint-1.0.0.tgz#8ca8f5f05fdcad35c13f26b65fb93c016196bdc9" + integrity sha512-acWyJUvRFo2aA/0kqeUxfCPwLtPk3ckZ/1I0BzBX9qW/Gi8qWqYnwnI/vEotIqmsQl+npbl0/SXeQHFrUdyB0g== + dependencies: + aot-test-generators "^0.1.0" + broccoli-concat "^3.7.1" + broccoli-persistent-filter "^2.1.0" + chalk "^2.4.1" + debug "^4.0.1" + ember-cli-version-checker "^3.0.1" + ember-template-lint "^1.2.0" + json-stable-stringify "^1.0.1" + md5-hex "^2.0.0" + strip-ansi "^4.0.0" + walk-sync "^1.1.3" + +ember-cli-test-loader@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-test-loader/-/ember-cli-test-loader-2.2.0.tgz#3fb8d5d1357e4460d3f0a092f5375e71b6f7c243" + integrity sha512-mlSXX9SciIRwGkFTX6XGyJYp4ry6oCFZRxh5jJ7VH8UXLTNx2ZACtDTwaWtNhYrWXgKyiDUvmD8enD56aePWRA== + dependencies: + ember-cli-babel "^6.8.1" + +ember-cli-typescript@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-typescript/-/ember-cli-typescript-3.0.0.tgz#3b838d1ce9e4d22a98e68da22ceac6dc0cfd9bfc" + integrity sha512-lo5YArbJzJi5ssvaGqTt6+FnhTALnSvYVuxM7lfyL1UCMudyNJ94ovH5C7n5il7ATd6WsNiAPRUO/v+s5Jq/aA== + dependencies: + "@babel/plugin-transform-typescript" "~7.5.0" + ansi-to-html "^0.6.6" + debug "^4.0.0" + ember-cli-babel-plugin-helpers "^1.0.0" + execa "^2.0.0" + fs-extra "^8.0.0" + resolve "^1.5.0" + rsvp "^4.8.1" + semver "^6.0.0" + stagehand "^1.0.0" + walk-sync "^2.0.0" + +ember-cli-typescript@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ember-cli-typescript/-/ember-cli-typescript-2.0.2.tgz#464984131fbdc05655eb61d1c3cdd911d3137f0d" + integrity sha512-7I5azCTxOgRDN8aSSnJZIKSqr+MGnT+jLTUbBYqF8wu6ojs2DUnTePxUcQMcvNh3Q3B1ySv7Q/uZFSjdU9gSjA== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.1.0" + "@babel/plugin-transform-typescript" "~7.4.0" + ansi-to-html "^0.6.6" + debug "^4.0.0" + ember-cli-babel-plugin-helpers "^1.0.0" + execa "^1.0.0" + fs-extra "^7.0.0" + resolve "^1.5.0" + rsvp "^4.8.1" + semver "^6.0.0" + stagehand "^1.0.0" + walk-sync "^1.0.0" + +ember-cli-uglify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-cli-uglify/-/ember-cli-uglify-3.0.0.tgz#8819665b2cc5fe70e3ba9fe7a94645209bc42fd6" + integrity sha512-n3QxdBfAgBdb2Cnso82Kt/nxm3ppIjnYWM8uhOEhF1aYxNXfM7AJrc+yiqTCDUR61Db8aCpHfAMvChz3kyme7g== + dependencies: + broccoli-uglify-sourcemap "^3.1.0" + lodash.defaultsdeep "^4.6.0" + +ember-cli-version-checker@^2.0.0, ember-cli-version-checker@^2.1.1, ember-cli-version-checker@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-2.2.0.tgz#47771b731fe0962705e27c8199a9e3825709f3b3" + integrity sha512-G+KtYIVlSOWGcNaTFHk76xR4GdzDLzAS4uxZUKdASuFX0KJE43C6DaqL+y3VTpUFLI2FIkAS6HZ4I1YBi+S3hg== + dependencies: + resolve "^1.3.3" + semver "^5.3.0" + +ember-cli-version-checker@^3.0.0, ember-cli-version-checker@^3.0.1, ember-cli-version-checker@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-3.1.3.tgz#7c9b4f5ff30fdebcd480b1c06c4de43bb51c522c" + integrity sha512-PZNSvpzwWgv68hcXxyjREpj3WWb81A7rtYNQq1lLEgrWIchF8ApKJjWP3NBpHjaatwILkZAV8klair5WFlXAKg== + dependencies: + resolve-package-path "^1.2.6" + semver "^5.6.0" + +ember-cli-version-checker@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ember-cli-version-checker/-/ember-cli-version-checker-4.1.0.tgz#7fc9836bdbc87451d286ba6a9a89b23591d8bbb7" + integrity sha512-yLf2YqotTSsjiXwx9Dt6H7AU0QcldFn5SLk/pG3Zqb0aHNeanBOPlx4/Ysa46ILGWYIh0fDH34AEVRueXTrQBQ== + dependencies: + resolve-package-path "^2.0.0" + semver "^6.3.0" + silent-error "^1.1.1" + +ember-cli@~3.15.2: + version "3.15.2" + resolved "https://registry.yarnpkg.com/ember-cli/-/ember-cli-3.15.2.tgz#c2a5871850da7537e0cb3cd0e7d59fd76cd3184e" + integrity sha512-ciuFaLokZDJfEzltH3QUxZYnQcigCzNrjyyVbeNtr3qUMICHZEzrreQjqIdmuOzmog+BOFddgAB2i/b7ewmV0Q== + dependencies: + "@babel/core" "^7.7.2" + "@babel/plugin-transform-modules-amd" "^7.5.0" + amd-name-resolver "^1.3.1" + babel-plugin-module-resolver "^3.2.0" + bower-config "^1.4.1" + bower-endpoint-parser "0.2.2" + broccoli "^3.2.0" + broccoli-amd-funnel "^2.0.1" + broccoli-babel-transpiler "^7.3.0" + broccoli-builder "^0.18.14" + broccoli-concat "^3.7.4" + broccoli-config-loader "^1.0.1" + broccoli-config-replace "^1.1.2" + broccoli-debug "^0.6.5" + broccoli-funnel "^2.0.2" + broccoli-funnel-reducer "^1.0.0" + broccoli-merge-trees "^3.0.2" + broccoli-middleware "^2.1.0" + broccoli-module-normalizer "^1.3.0" + broccoli-module-unification-reexporter "^1.0.0" + broccoli-slow-trees "^3.0.1" + broccoli-source "^3.0.0" + broccoli-stew "^3.0.0" + calculate-cache-key-for-tree "^2.0.0" + capture-exit "^2.0.0" + chalk "^2.4.2" + ci-info "^2.0.0" + clean-base-url "^1.0.0" + compression "^1.7.4" + configstore "^5.0.0" + console-ui "^3.1.1" + core-object "^3.1.5" + dag-map "^2.0.2" + diff "^4.0.1" + ember-cli-is-package-missing "^1.0.0" + ember-cli-lodash-subset "^2.0.1" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-preprocess-registry "^3.3.0" + ember-cli-string-utils "^1.1.0" + ember-source-channel-url "^2.0.1" + ensure-posix-path "^1.0.2" + execa "^1.0.0" + exit "^0.1.2" + express "^4.16.4" + filesize "^4.2.0" + find-up "^4.1.0" + find-yarn-workspace-root "^1.2.1" + fs-extra "^8.1.0" + fs-tree-diff "^2.0.1" + get-caller-file "^2.0.5" + git-repo-info "^2.1.0" + glob "^7.1.4" + heimdalljs "^0.2.6" + heimdalljs-fs-monitor "^0.2.3" + heimdalljs-graph "^1.0.0" + heimdalljs-logger "^0.1.10" + http-proxy "^1.18.0" + inflection "^1.12.0" + is-git-url "^1.0.0" + isbinaryfile "^3.0.3" + js-yaml "^3.13.1" + json-stable-stringify "^1.0.1" + leek "0.0.24" + lodash.template "^4.5.0" + markdown-it "^9.1.0" + markdown-it-terminal "0.1.0" + minimatch "^3.0.4" + morgan "^1.9.1" + nopt "^3.0.6" + npm-package-arg "^6.1.1" + p-defer "^3.0.0" + portfinder "^1.0.25" + promise-map-series "^0.2.3" + promise.prototype.finally "^3.1.1" + quick-temp "^0.1.8" + resolve "^1.12.0" + resolve-package-path "^1.2.7" + rsvp "^4.8.5" + sane "^4.1.0" + semver "^6.3.0" + silent-error "^1.1.1" + sort-package-json "^1.23.1" + symlink-or-copy "^1.2.0" + temp "0.9.0" + testem "^2.17.0" + tiny-lr "^1.1.1" + tree-sync "^2.0.0" + uuid "^3.3.3" + walk-sync "^2.0.2" + watch-detector "^1.0.0" + yam "^1.0.0" + +ember-compatibility-helpers@^1.1.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ember-compatibility-helpers/-/ember-compatibility-helpers-1.2.1.tgz#87c92c4303f990ff455c28ca39fb3ee11441aa16" + integrity sha512-6wzYvnhg1ihQUT5yGqnLtleq3Nv5KNv79WhrEuNU9SwR4uIxCO+KpyC7r3d5VI0EM7/Nmv9Nd0yTkzmTMdVG1A== + dependencies: + babel-plugin-debug-macros "^0.2.0" + ember-cli-version-checker "^2.1.1" + semver "^5.4.1" + +ember-disable-prototype-extensions@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/ember-disable-prototype-extensions/-/ember-disable-prototype-extensions-1.1.3.tgz#1969135217654b5e278f9fe2d9d4e49b5720329e" + integrity sha1-GWkTUhdlS14nj5/i2dTkm1cgMp4= + +ember-export-application-global@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ember-export-application-global/-/ember-export-application-global-2.0.1.tgz#b120a70e322ab208defc9e2daebe8d0dfc2dcd46" + integrity sha512-B7wiurPgsxsSGzJuPFkpBWnaeuCu2PGpG2BjyrfA1VcL7//o+5RSnZqiCEY326y7qmxb2GoCgo0ft03KBU0rRw== + +ember-load-initializers@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ember-load-initializers/-/ember-load-initializers-2.1.1.tgz#d1a8bead00bc44222b0ab181840869992beb30f5" + integrity sha512-Ho5sBeaZPN3HmZkYkcLrjSBF3DTNmzC5h0DizzDj8cjpnCvaqeofphJDnH41k6kLv/QHMk4pMRISPcwc+bOceQ== + dependencies: + ember-cli-babel "^7.11.0" + ember-cli-typescript "^2.0.2" + +ember-maybe-import-regenerator@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ember-maybe-import-regenerator/-/ember-maybe-import-regenerator-0.1.6.tgz#35d41828afa6d6a59bc0da3ce47f34c573d776ca" + integrity sha1-NdQYKK+m1qWbwNo85H80xXPXdso= + dependencies: + broccoli-funnel "^1.0.1" + broccoli-merge-trees "^1.0.0" + ember-cli-babel "^6.0.0-beta.4" + regenerator-runtime "^0.9.5" + +ember-qunit@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/ember-qunit/-/ember-qunit-4.6.0.tgz#ad79fd3ff00073a8779400cc5a4b44829517590f" + integrity sha512-i5VOGn0RP8XH+5qkYDOZshbqAvO6lHgF65D0gz8vRx4DszCIvJMJO+bbftBTfYMxp6rqG85etAA6pfNxE0DqsQ== + dependencies: + "@ember/test-helpers" "^1.7.1" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.2" + common-tags "^1.4.0" + ember-cli-babel "^7.12.0" + ember-cli-test-loader "^2.2.0" + qunit "^2.9.3" + +ember-resolver@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ember-resolver/-/ember-resolver-7.0.0.tgz#07ca86b3bae373395b44bba784b8c133f75d61c2" + integrity sha512-tqyWk9E1P5LL42x7AnVoE25a/YWe0WcwAr8LXasm5V7Az3vFR/zbFtwN0oI3tpoSP/nCoGWDct6dRYlXrQjqBQ== + dependencies: + babel-plugin-debug-macros "^0.3.3" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.0" + ember-cli-babel "^7.13.2" + ember-cli-version-checker "^3.1.3" + resolve "^1.14.0" + +ember-rfc176-data@^0.3.12: + version "0.3.12" + resolved "https://registry.yarnpkg.com/ember-rfc176-data/-/ember-rfc176-data-0.3.12.tgz#90d82878e69e2ac9a5438e8ce14d12c6031c5bd2" + integrity sha512-g9HeZj/gU5bfIIrGXkP7MhS2b3Vu5DfNUrYr14hy99TgIvtZETO+96QF4WOEUXGjIJdfTRjerVnQlqngPQSv1g== + +ember-router-generator@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ember-router-generator/-/ember-router-generator-2.0.0.tgz#d04abfed4ba8b42d166477bbce47fccc672dbde0" + integrity sha512-89oVHVJwmLDvGvAUWgS87KpBoRhy3aZ6U0Ql6HOmU4TrPkyaa8pM0W81wj9cIwjYprcQtN9EwzZMHnq46+oUyw== + dependencies: + "@babel/parser" "^7.4.5" + "@babel/traverse" "^7.4.5" + recast "^0.18.1" + +ember-source-channel-url@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-1.2.0.tgz#77eb9d0889e5f5370e6c70fcb2696c63ff4a34a1" + integrity sha512-CLClcHzVf+8GoFk4176R16nwXoel70bd7DKVAY6D8M0m5fJJhbTrAPYpDA0lY8A60HZo9j/s8A8LWiGh1YmdZg== + dependencies: + got "^8.0.1" + +ember-source-channel-url@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ember-source-channel-url/-/ember-source-channel-url-2.0.1.tgz#18b88f8a00b7746e7a456b3551abb3aea18729cc" + integrity sha512-YlLUHW9gNvxEaohIj5exykoTZb4xj9ZRTcR4J3svv9S8rjAHJUnHmqC5Fd9onCs+NGxHo7KwR/fDwsfadbDu5Q== + dependencies: + got "^8.0.1" + +ember-source@~3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/ember-source/-/ember-source-3.15.0.tgz#f6500c6d289ce58231bf1e6695c4974df2be7390" + integrity sha512-daTELJBDMGqAmQb/Puxdk1YR204/zs1DEiEMQWlqbtmhphAoDUbGi9ifJu20ajP/IcOCWw9Vp7aPzguTohWF7w== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/plugin-transform-block-scoping" "^7.6.2" + "@babel/plugin-transform-object-assign" "^7.2.0" + "@ember/edition-utils" "^1.1.1" + babel-plugin-debug-macros "^0.3.3" + babel-plugin-filter-imports "^3.0.0" + broccoli-concat "^3.7.4" + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.2" + chalk "^2.4.2" + ember-cli-babel "^7.11.0" + ember-cli-get-component-path-option "^1.0.0" + ember-cli-is-package-missing "^1.0.0" + ember-cli-normalize-entity-name "^1.0.0" + ember-cli-path-utils "^1.0.0" + ember-cli-string-utils "^1.1.0" + ember-cli-version-checker "^3.1.3" + ember-router-generator "^2.0.0" + inflection "^1.12.0" + jquery "^3.4.1" + resolve "^1.11.1" + semver "^6.1.1" + silent-error "^1.1.1" + +ember-template-lint@^1.2.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/ember-template-lint/-/ember-template-lint-1.14.0.tgz#fd3e8ec600b0b3de16b5701bf02acc99d192008e" + integrity sha512-M4CebpUZ6G8NEX05FsvlB6nFRO9Xi3eJWbGbnHI1Sakyp5Hl739fTPR5yPn/Gscc/sgNU25Rq1RSm0hoevrYGA== + dependencies: + "@glimmer/syntax" "^0.47.9" + chalk "^2.4.2" + globby "^9.2.0" + minimatch "^3.0.4" + resolve "^1.15.1" + strip-bom "^3.0.0" + +ember-test-waiters@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ember-test-waiters/-/ember-test-waiters-1.2.0.tgz#c12ead4313934c24cff41857020cacdbf8e6effe" + integrity sha512-aEw7YuutLuJT4NUuPTNiGFwgTYl23ThqmBxSkfFimQAn+keWjAftykk3dlFELuhsJhYW/S8YoVjN0bSAQRLNtw== + dependencies: + ember-cli-babel "^7.11.0" + semver "^6.3.0" + +ember-try-config@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ember-try-config/-/ember-try-config-3.0.0.tgz#012d8c90cae9eb624e2b62040bf7e76a1aa58edc" + integrity sha512-pNwHS29O1ACczkrxBKRtDY0TzTb7uPnA5eHEe+4NF6qpLK5FVnL3EtgZ8+yVYtnm1If5mZ07rIubw45vaSek7w== + dependencies: + ember-source-channel-url "^1.0.1" + lodash "^4.6.1" + package-json "^4.0.1" + remote-git-tags "^2.0.0" + rsvp "^4.8.1" + semver "^5.5.0" + +ember-try@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ember-try/-/ember-try-1.4.0.tgz#be15965bd1727c27a65a78c4c8392f03763cc565" + integrity sha512-o0SoCH4K8umCf8etphla8FDygKfQGkwY+w47wEuYFVKaESrOZaK63ObnAK7DTKkjJU74Fss2abf+r+pAWpX43g== + dependencies: + chalk "^2.4.2" + cli-table3 "^0.5.1" + core-object "^3.1.5" + debug "^4.1.1" + ember-try-config "^3.0.0" + execa "^1.0.0" + extend "^3.0.0" + fs-extra "^5.0.0" + promise-map-series "^0.2.1" + resolve "^1.10.1" + rimraf "^2.6.3" + rsvp "^4.7.0" + walk-sync "^1.1.3" + +emit-function@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/emit-function/-/emit-function-0.0.2.tgz#e3a50b3d61be1bf8ca88b924bf713157a5bec124" + integrity sha1-46ULPWG+G/jKiLkkv3ExV6W+wSQ= + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.1.tgz#922ddb47eecdcb541136a93aeead24718fd05461" + integrity sha512-RJNmA+A9Js+8Aoq815xpGAsgWH1VoSYM//2VgIiu9lNOaHFfLpTjH4tOzktBpjIs5lvOfiNY1dwf+NuU6D38Mw== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~4.1.0" + engine.io-parser "~2.2.0" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed" + integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.4.1.tgz#a61cbc13fa0cb27d9453fd079a29ee980564b069" + integrity sha512-8MfIfF1/IIfxuc2gv5K+XlFZczw/BpTvqBdl0E2fBLkYQp4miv4LuDTVtYt4yMyaIFLEr4vtaSgV4mjvll8Crw== + dependencies: + accepts "~1.3.4" + base64id "2.0.0" + cookie "0.3.1" + debug "~4.1.0" + engine.io-parser "~2.2.0" + ws "^7.1.2" + +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +ensure-posix-path@^1.0.0, ensure-posix-path@^1.0.1, ensure-posix-path@^1.0.2, ensure-posix-path@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ensure-posix-path/-/ensure-posix-path-1.1.1.tgz#3c62bdb19fa4681544289edb2b382adc029179ce" + integrity sha512-VWU0/zXzVbeJNXvME/5EmLuEj2TauvoaTz6aFYK1Z92JCBlDlZ3Gu0tuGR42kpW1754ywTs+QB0g5TP0oj9Zaw== + +entities@^1.1.2, entities@~1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" + integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== + +errno@^0.1.3, errno@~0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== + dependencies: + prr "~1.0.1" + +error@^7.0.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" + integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== + dependencies: + string-template "~0.2.1" + +es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: + version "1.17.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" + integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.1.5" + is-regex "^1.0.5" + object-inspect "^1.7.0" + object-keys "^1.1.1" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escodegen@^1.11.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" + integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-plugin-ember@^7.7.1: + version "7.13.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-ember/-/eslint-plugin-ember-7.13.0.tgz#a1df7794f06cdc6e1b8acfe6c59db5cf861f53dc" + integrity sha512-qIbw4uP0qUJoiWF4+7MTJWqwEN86RGmBNId0cwSoHoVNWtcw50R1ajYgxM1Q5FVUdoisVeSl9lKVRh5zkDFl+g== + dependencies: + "@ember-data/rfc395-data" "^0.0.4" + ember-rfc176-data "^0.3.12" + snake-case "^3.0.3" + +eslint-plugin-es@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-2.0.0.tgz#0f5f5da5f18aa21989feebe8a73eadefb3432976" + integrity sha512-f6fceVtg27BR02EYnBhgWLFQfK6bN4Ll0nQFrBHOlCsAyxeZkn0NHns5O0YZOPrV1B3ramd6cgFwaoFLcSkwEQ== + dependencies: + eslint-utils "^1.4.2" + regexpp "^3.0.0" + +eslint-plugin-node@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-10.0.0.tgz#fd1adbc7a300cf7eb6ac55cf4b0b6fc6e577f5a6" + integrity sha512-1CSyM/QCjs6PXaT18+zuAXsjXGIGo5Rw630rSKwokSs2jrYURQc4R5JZpoanNCqwNmepg+0eZ9L7YiRUJb8jiQ== + dependencies: + eslint-plugin-es "^2.0.0" + eslint-utils "^1.4.2" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-scope@^4.0.0, eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-utils@^1.3.1, eslint-utils@^1.4.2: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^5.6.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" + integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.9.1" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^4.0.3" + eslint-utils "^1.3.1" + eslint-visitor-keys "^1.0.0" + espree "^5.0.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.2.2" + js-yaml "^3.13.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.11" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^5.5.1" + strip-ansi "^4.0.0" + strip-json-comments "^2.0.1" + table "^5.2.3" + text-table "^0.2.0" + +esm@^3.2.4: + version "3.2.25" + resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10" + integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA== + +espree@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" + integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== + dependencies: + acorn "^6.0.7" + acorn-jsx "^5.0.0" + eslint-visitor-keys "^1.0.0" + +esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esprima@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.0.0.tgz#53cf247acda77313e551c3aa2e73342d3fb4f7d9" + integrity sha1-U88kes2ncxPlUcOqLnM0LT+099k= + +esquery@^1.0.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== + dependencies: + estraverse "^4.1.0" + +estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" + integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.0.tgz#d65176163887ee59f386d64c82610b696a4a74eb" + integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== + +events-to-array@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.1.2.tgz#2d41f563e1fe400ed4962fe1a4d5c6a7539df7f6" + integrity sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y= + +events@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-2.1.0.tgz#e5d3ecd837d2a60ec50f3da78fd39767747bbe99" + integrity sha512-Y/URAVapfbYy2Xp/gb6A0E7iR8xeqOCXsuuaoMn7A5PzrXUK84E1gyiEfq0wQd/GHA6GsoHWwhNq8anb0mleIw== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^3.0.0" + onetime "^5.1.0" + p-finally "^2.0.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +exists-sync@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/exists-sync/-/exists-sync-0.0.4.tgz#9744c2c428cc03b01060db454d4b12f0ef3c8879" + integrity sha1-l0TCxCjMA7AQYNtFTUsS8O88iHk= + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.10.7, express@^4.16.4: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + +fast-glob@^2.2.6: + version "2.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" + integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.1.2" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.3" + micromatch "^3.1.10" + +fast-glob@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" + integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fast-ordered-set@^1.0.0, fast-ordered-set@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fast-ordered-set/-/fast-ordered-set-1.0.3.tgz#3fbb36634f7be79e4f7edbdb4a357dee25d184eb" + integrity sha1-P7s2Y097555PftvbSjV97iXRhOs= + dependencies: + blank-object "^1.0.1" + +fast-sourcemap-concat@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/fast-sourcemap-concat/-/fast-sourcemap-concat-1.4.0.tgz#122c330d4a2afaff16ad143bc9674b87cd76c8ad" + integrity sha512-x90Wlx/2C83lfyg7h4oguTZN4MyaVfaiUSJQNpU+YEA0Odf9u659Opo44b0LfoVg9G/bOE++GdID/dkyja+XcA== + dependencies: + chalk "^2.0.0" + fs-extra "^5.0.0" + heimdalljs-logger "^0.1.9" + memory-streams "^0.1.3" + mkdirp "^0.5.0" + source-map "^0.4.2" + source-map-url "^0.3.0" + sourcemap-validator "^1.1.0" + +fastq@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.7.0.tgz#fcd79a08c5bd7ec5b55cd3f5c4720db551929801" + integrity sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ== + dependencies: + reusify "^1.0.4" + +faye-websocket@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +figgy-pudding@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= + dependencies: + escape-string-regexp "^1.0.5" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filesize@^4.1.2, filesize@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-4.2.1.tgz#ab1cb2069db5d415911c1a13e144c0e743bc89bc" + integrity sha512-bP82Hi8VRZX/TUBKfE24iiUGsB/sfm2WUrwTQyAzQrhO3V9IhcBBNBXMyzLY5orACxRyYJ3d2HeRVX+eFv4lmA== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2, finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-babel-config@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-1.2.0.tgz#a9b7b317eb5b9860cda9d54740a8c8337a2283a2" + integrity sha512-jB2CHJeqy6a820ssiqwrKMeyC6nNdmrcgkKWJWmpoxpE8RKciYJXCcXRq1h2AzCo5I5BJeN2tkGEO3hLTuePRA== + dependencies: + json5 "^0.5.1" + path-exists "^3.0.0" + +find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-index@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/find-index/-/find-index-1.1.1.tgz#4b221f8d46b7f8bea33d8faed953f3ca7a081cbc" + integrity sha512-XYKutXMrIK99YMUPf91KX5QVJoG31/OsgftD6YoTPAObfQIxM4ziA9f0J1AsqKhJmo+IeaIPP0CFopTD4bdUBw== + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-yarn-workspace-root@^1.1.0, find-yarn-workspace-root@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" + integrity sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q== + dependencies: + fs-extra "^4.0.3" + micromatch "^3.1.4" + +findup-sync@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-4.0.0.tgz#956c9cdde804052b881b428512905c4a5f2cdef0" + integrity sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^4.0.2" + resolve-dir "^1.0.1" + +fireworm@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/fireworm/-/fireworm-0.7.1.tgz#ccf20f7941f108883fcddb99383dbe6e1861c758" + integrity sha1-zPIPeUHxCIg/zduZOD2+bhhhx1g= + dependencies: + async "~0.2.9" + is-type "0.0.1" + lodash.debounce "^3.1.1" + lodash.flatten "^3.0.2" + minimatch "^3.0.2" + +fixturify-project@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/fixturify-project/-/fixturify-project-1.10.0.tgz#091c452a9bb15f09b6b9cc7cf5c0ad559f1d9aad" + integrity sha512-L1k9uiBQuN0Yr8tA9Noy2VSQ0dfg0B8qMdvT7Wb5WQKc7f3dn3bzCbSrqlb+etLW+KDV4cBC7R1OvcMg3kcxmA== + dependencies: + fixturify "^1.2.0" + tmp "^0.0.33" + +fixturify@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fixturify/-/fixturify-1.3.0.tgz#163c468093c7c4d90b70cde39fd6325f6528b25d" + integrity sha512-tL0svlOy56pIMMUQ4bU1xRe6NZbFSa/ABTWMxW2mH38lFGc9TrNAKWcMBQ7eIjo3wqSS8f2ICabFaatFyFmrVQ== + dependencies: + "@types/fs-extra" "^5.0.5" + "@types/minimatch" "^3.0.3" + "@types/rimraf" "^2.0.2" + fs-extra "^7.0.1" + matcher-collection "^2.0.0" + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" + integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA== + dependencies: + debug "^3.0.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" + integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0, from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-extra@^0.24.0: + version "0.24.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.24.0.tgz#d4e4342a96675cb7846633a6099249332b539952" + integrity sha1-1OQ0KpZnXLeEZjOmCZJJMytTmVI= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^4.0.2, fs-extra@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-6.0.1.tgz#8abc128f7946e310135ddc93b98bddb410e7a34b" + integrity sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^7.0.0, fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^8.0.0, fs-extra@^8.0.1, fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-merger@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fs-merger/-/fs-merger-3.0.3.tgz#d43c978e3cd5dbc29fb34144182eba749ab8c4b5" + integrity sha512-d9Qx+XlPRU4mkp+JYhUvp5NyS31uhqffIgs6EBnZcjrlO9RwSv0lkWi6PIDxgdNF+vjn9QCZevunGDpfoy4BGg== + dependencies: + broccoli-node-api "^1.7.0" + broccoli-node-info "^2.1.0" + fs-extra "^8.0.1" + fs-tree-diff "^2.0.1" + rimraf "^2.6.3" + walk-sync "^2.0.2" + +fs-minipass@^1.2.5: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs-tree-diff@^0.5.2, fs-tree-diff@^0.5.3, fs-tree-diff@^0.5.4, fs-tree-diff@^0.5.6, fs-tree-diff@^0.5.7: + version "0.5.9" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-0.5.9.tgz#a4ec6182c2f5bd80b9b83c8e23e4522e6f5fd946" + integrity sha512-872G8ax0kHh01m9n/2KDzgYwouKza0Ad9iFltBpNykvROvf2AGtoOzPJgGx125aolGPER3JuC7uZFrQ7bG1AZw== + dependencies: + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + +fs-tree-diff@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-1.0.2.tgz#0e2931733a85b55feb3472c0b89a20b0c03ac0de" + integrity sha512-Zro2ACaPVDgVOx9+s5s5AfPlAD0kMJdbwGvTGF6KC1SjxjiGWxJvV4mUTDkFVSy3OUw2C/f1qpdjF81hGqSBAw== + dependencies: + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + +fs-tree-diff@^2.0.0, fs-tree-diff@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz#343e4745ab435ec39ebac5f9059ad919cd034afa" + integrity sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A== + dependencies: + "@types/symlink-or-copy" "^1.2.0" + heimdalljs-logger "^0.1.7" + object-assign "^4.1.0" + path-posix "^1.0.0" + symlink-or-copy "^1.1.8" + +fs-updater@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fs-updater/-/fs-updater-1.0.4.tgz#2329980f99ae9176e9a0e84f7637538a182ce63b" + integrity sha512-0pJX4mJF/qLsNEwTct8CdnnRdagfb+LmjRPJ8sO+nCnAZLW0cTmz4rTgU25n+RvTuWSITiLKrGVJceJPBIPlKg== + dependencies: + can-symlink "^1.0.0" + clean-up-path "^1.0.0" + heimdalljs "^0.2.5" + heimdalljs-logger "^0.1.9" + rimraf "^2.6.2" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.12" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.12.tgz#db7e0d8ec3b0b45724fd4d83d43554a8f1f0de5c" + integrity sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9" + integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +git-fetch-pack@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/git-fetch-pack/-/git-fetch-pack-0.1.1.tgz#7703a32cf0db80f060d2766a34ac00d02cebcdf5" + integrity sha1-dwOjLPDbgPBg0nZqNKwA0CzrzfU= + dependencies: + bops "0.0.3" + emit-function "0.0.2" + git-packed-ref-parse "0.0.0" + through "~2.2.7" + +git-hooks-list@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-1.0.3.tgz#be5baaf78203ce342f2f844a9d2b03dba1b45156" + integrity sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ== + +git-packed-ref-parse@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/git-packed-ref-parse/-/git-packed-ref-parse-0.0.0.tgz#b85046931f3e4a65679b5de54af3a5d3df372646" + integrity sha1-uFBGkx8+SmVnm13lSvOl0983JkY= + dependencies: + line-stream "0.0.0" + through "~2.2.7" + +git-read-pkt-line@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/git-read-pkt-line/-/git-read-pkt-line-0.0.8.tgz#494037854ed57bd90cd55676540d86ab0cb36caa" + integrity sha1-SUA3hU7Ve9kM1VZ2VA2GqwyzbKo= + dependencies: + bops "0.0.3" + through "~2.2.7" + +git-repo-info@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/git-repo-info/-/git-repo-info-2.1.1.tgz#220ffed8cbae74ef8a80e3052f2ccb5179aed058" + integrity sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg== + +git-transport-protocol@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/git-transport-protocol/-/git-transport-protocol-0.1.0.tgz#99f4dd6389b9161eded74a9e617d6ba5ed0a6c2c" + integrity sha1-mfTdY4m5Fh7e10qeYX1rpe0KbCw= + dependencies: + duplex "~1.0.0" + emit-function "0.0.2" + git-read-pkt-line "0.0.8" + git-write-pkt-line "0.1.0" + through "~2.2.7" + +git-write-pkt-line@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/git-write-pkt-line/-/git-write-pkt-line-0.1.0.tgz#a84c1856c09011908389b2f06f911d91f6394694" + integrity sha1-qEwYVsCQEZCDibLwb5EdkfY5RpQ= + dependencies: + bops "0.0.3" + through "~2.2.7" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= + +glob@^5.0.10: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.4, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +globals@^11.1.0, globals@^11.7.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== + +globby@11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" + integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globby@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" + integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^1.0.2" + dir-glob "^2.2.2" + fast-glob "^2.2.6" + glob "^7.1.3" + ignore "^4.0.3" + pify "^4.0.1" + slash "^2.0.0" + +got@^6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" + integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= + dependencies: + create-error-class "^3.0.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-redirect "^1.0.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + lowercase-keys "^1.0.0" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + unzip-response "^2.0.1" + url-parse-lax "^1.0.0" + +got@^8.0.1: + version "8.3.2" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3, graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + +handlebars@^4.0.11, handlebars@^4.0.4, handlebars@^4.3.1, handlebars@^4.5.1, handlebars@^4.7.3: + version "4.7.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e" + integrity sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-3.0.0.tgz#36077ef1d15f333484aa7fa77a28606f1c655b37" + integrity sha1-Ngd+8dFfMzSEqn+neihgbxxlWzc= + dependencies: + ansi-regex "^3.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +has-symbols@^1.0.0, has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash-for-dep@^1.0.2, hash-for-dep@^1.2.3, hash-for-dep@^1.4.7, hash-for-dep@^1.5.0, hash-for-dep@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/hash-for-dep/-/hash-for-dep-1.5.1.tgz#497754b39bee2f1c4ade4521bfd2af0a7c1196e3" + integrity sha512-/dQ/A2cl7FBPI2pO0CANkvuuVi/IFS5oTyJ0PsOb6jW6WbVW1js5qJXMJTNbWHXBIPdFTWFbabjB+mE0d+gelw== + dependencies: + broccoli-kitchen-sink-helpers "^0.3.1" + heimdalljs "^0.2.3" + heimdalljs-logger "^0.1.7" + path-root "^0.1.1" + resolve "^1.10.0" + resolve-package-path "^1.0.11" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +heimdalljs-fs-monitor@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/heimdalljs-fs-monitor/-/heimdalljs-fs-monitor-0.2.3.tgz#1aedd4b1c61d86c51f6141fb75c5a3350dc41b15" + integrity sha512-fYAvqSP0CxeOjLrt61B4wux/jqZzdZnS2xfb2oc14NP6BTZ8gtgtR2op6gKFakOR8lm8GN9Xhz1K4A1ZvJ4RQw== + dependencies: + heimdalljs "^0.2.3" + heimdalljs-logger "^0.1.7" + +heimdalljs-graph@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/heimdalljs-graph/-/heimdalljs-graph-1.0.0.tgz#0059857952988e54f3a74bb23edaf669f8eaf6af" + integrity sha512-v2AsTERBss0ukm/Qv4BmXrkwsT5x6M1V5Om6E8NcDQ/ruGkERsfsuLi5T8jx8qWzKMGYlwzAd7c/idymxRaPzA== + +heimdalljs-logger@^0.1.10, heimdalljs-logger@^0.1.7, heimdalljs-logger@^0.1.9: + version "0.1.10" + resolved "https://registry.yarnpkg.com/heimdalljs-logger/-/heimdalljs-logger-0.1.10.tgz#90cad58aabb1590a3c7e640ddc6a4cd3a43faaf7" + integrity sha512-pO++cJbhIufVI/fmB/u2Yty3KJD0TqNPecehFae0/eps0hkZ3b4Zc/PezUMOpYuHFQbA7FxHZxa305EhmjLj4g== + dependencies: + debug "^2.2.0" + heimdalljs "^0.2.6" + +heimdalljs@^0.2.0, heimdalljs@^0.2.1, heimdalljs@^0.2.3, heimdalljs@^0.2.5, heimdalljs@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/heimdalljs/-/heimdalljs-0.2.6.tgz#b0eebabc412813aeb9542f9cc622cb58dbdcd9fe" + integrity sha512-o9bd30+5vLBvBtzCPwwGqpry2+n0Hi6H1+qwt6y+0kwRHGGF8TFIhJPmnuM0xO97zaKrDZMwO/V56fAnn8m/tA== + dependencies: + rsvp "~3.2.1" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg= + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.7.1: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +"http-parser-js@>=0.4.0 <0.4.11": + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" + integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q= + +http-proxy@^1.13.1, http-proxy@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" + integrity sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https/-/https-1.0.0.tgz#3c37c7ae1a8eeb966904a2ad1e975a194b7ed3a4" + integrity sha1-PDfHrhqO65ZpBKKtHpdaGUt+06Q= + +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +ignore-walk@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" + integrity sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw== + dependencies: + minimatch "^3.0.4" + +ignore@^4.0.3, ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.1, ignore@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" + integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== + +import-fresh@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +infer-owner@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflection@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416" + integrity sha1-ogCTVlbW9fa8TcdQLhrstwMihBY= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inline-source-map-comment@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/inline-source-map-comment/-/inline-source-map-comment-1.0.5.tgz#50a8a44c2a790dfac441b5c94eccd5462635faf6" + integrity sha1-UKikTCp5DfrEQbXJTszVRiY1+vY= + dependencies: + chalk "^1.0.0" + get-stdin "^4.0.1" + minimist "^1.1.1" + sum-up "^1.0.1" + xtend "^4.0.0" + +inquirer@^6, inquirer@^6.2.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + +inquirer@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" + integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== + dependencies: + ansi-escapes "^4.2.1" + chalk "^3.0.0" + cli-cursor "^3.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.15" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.5.3" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + +invariant@^2.2.2, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-git-url@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-git-url/-/is-git-url-1.0.0.tgz#53f684cd143285b52c3244b4e6f28253527af66b" + integrity sha1-U/aEzRQyhbUsMkS05vKCU1J69ms= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= + +is-plain-obj@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-redirect@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" + integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= + +is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== + dependencies: + has "^1.0.3" + +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-type@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/is-type/-/is-type-0.0.1.tgz#f651d85c365d44955d14a51d8d7061f3f6b4779c" + integrity sha1-9lHYXDZdRJVdFKUdjXBh8/a0d5w= + dependencies: + core-util-is "~1.0.0" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + +isbinaryfile@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80" + integrity sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw== + dependencies: + buffer-alloc "^1.2.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istextorbinary@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/istextorbinary/-/istextorbinary-2.1.0.tgz#dbed2a6f51be2f7475b68f89465811141b758874" + integrity sha1-2+0qb1G+L3R1to+JRlgRFBt1iHQ= + dependencies: + binaryextensions "1 || 2" + editions "^1.1.1" + textextensions "1 || 2" + +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jquery@^3.4.1: + version "3.5.0" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.0.tgz#9980b97d9e4194611c36530e7dc46a58d7340fc9" + integrity sha512-Xb7SVYMvygPxbFMpTFQiHh1J7HClEaThguL15N/Gg37Lri/qKyhRGZYzHRyLH8Stq3Aow0LsHO2O2ci86fCrNQ== + +js-reporters@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/js-reporters/-/js-reporters-1.2.1.tgz#f88c608e324a3373a95bcc45ad305e5c979c459b" + integrity sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs= + +js-string-escape@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" + integrity sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8= + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= + +js-yaml@^3.13.0, js-yaml@^3.13.1, js-yaml@^3.2.5, js-yaml@^3.2.7: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^12.0.0: + version "12.2.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-12.2.0.tgz#7cf3f5b5eafd47f8f09ca52315d367ff6e95de23" + integrity sha512-QPOggIJ8fquWPLaYYMoh+zqUmdphDtu1ju0QGTitZT1Yd8I5qenPpXM1etzUegu3MjVp8XPzgZxdn8Yj7e40ig== + dependencies: + abab "^2.0.0" + acorn "^6.0.2" + acorn-globals "^4.3.0" + array-equal "^1.0.0" + cssom "^0.3.4" + cssstyle "^1.1.1" + data-urls "^1.0.1" + domexception "^1.0.1" + escodegen "^1.11.0" + html-encoding-sniffer "^1.0.2" + nwsapi "^2.0.9" + parse5 "5.1.0" + pn "^1.1.0" + request "^2.88.0" + request-promise-native "^1.0.5" + saxes "^3.1.3" + symbol-tree "^3.2.2" + tough-cookie "^2.4.3" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + ws "^6.1.0" + xml-name-validator "^3.0.0" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s= + +jsesc@^2.5.0, jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.3.x: + version "0.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.3.0.tgz#1bf5ee63b4539fe2e26d0c1e99c240b97a457972" + integrity sha1-G/XuY7RTn+LibQwemcJAuXpFeXI= + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + +json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha1-NzaitCi4e72gzIO1P6PWM6NcKug= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== + dependencies: + json-buffer "3.0.0" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +leek@0.0.24: + version "0.0.24" + resolved "https://registry.yarnpkg.com/leek/-/leek-0.0.24.tgz#e400e57f0e60d8ef2bd4d068dc428a54345dbcda" + integrity sha1-5ADlfw5g2O8r1NBo3EKKVDRdvNo= + dependencies: + debug "^2.1.0" + lodash.assign "^3.2.0" + rsvp "^3.0.21" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +line-stream@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/line-stream/-/line-stream-0.0.0.tgz#888b7cc7951c6a05ce4d696dd1e6b8262371bb45" + integrity sha1-iIt8x5UcagXOTWlt0ea4JiNxu0U= + dependencies: + through "~2.2.0" + +linkify-it@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf" + integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw== + dependencies: + uc.micro "^1.0.1" + +livereload-js@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" + integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== + +loader-runner@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@^1.1.0, loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +loader.js@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/loader.js/-/loader.js-4.7.0.tgz#a1a52902001c83631efde9688b8ab3799325ef1f" + integrity sha512-9M2KvGT6duzGMgkOcTkWb+PR/Q2Oe54df/tLgHGVmFpAmtqJ553xJh6N63iFYI2yjo2PeJXbS5skHi/QpJq4vA== + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= + +lodash._baseflatten@^3.0.0: + version "3.1.4" + resolved "https://registry.yarnpkg.com/lodash._baseflatten/-/lodash._baseflatten-3.1.4.tgz#0770ff80131af6e34f3b511796a7ba5214e65ff7" + integrity sha1-B3D/gBMa9uNPO1EXlqe6UhTmX/c= + dependencies: + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash._bindcallback@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" + integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= + +lodash._createassigner@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" + integrity sha1-g4pbri/aymOsIt7o4Z+k5taXCxE= + dependencies: + lodash._bindcallback "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash.restparam "^3.0.0" + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash.assign@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" + integrity sha1-POnwI0tLIiPilrj6CsH+6OvKZPo= + dependencies: + lodash._baseassign "^3.0.0" + lodash._createassigner "^3.0.0" + lodash.keys "^3.0.0" + +lodash.assignin@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" + integrity sha1-uo31+4QesKPoBEIysOJjqNxqKKI= + +lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU= + +lodash.clonedeep@^4.4.1: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + +lodash.debounce@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-3.1.1.tgz#812211c378a94cc29d5aa4e3346cf0bfce3a7df5" + integrity sha1-gSIRw3ipTMKdWqTjNGzwv846ffU= + dependencies: + lodash._getnative "^3.0.0" + +lodash.defaultsdeep@^4.6.0, lodash.defaultsdeep@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6" + integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA== + +lodash.find@^4.5.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" + integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E= + +lodash.flatten@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-3.0.2.tgz#de1cf57758f8f4479319d35c3e9cc60c4501938c" + integrity sha1-3hz1d1j49EeTGdNcPpzGDEUBk4w= + dependencies: + lodash._baseflatten "^3.0.0" + lodash._isiterateecall "^3.0.0" + +lodash.foreach@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" + integrity sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM= + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.merge@^4.6.0, lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.omit@^4.1.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" + integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.template@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.uniq@^4.2.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash.uniqby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" + integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI= + +lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.6.1: + version "4.17.15" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== + +log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lower-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" + integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== + dependencies: + tslib "^1.10.0" + +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +markdown-it-terminal@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/markdown-it-terminal/-/markdown-it-terminal-0.1.0.tgz#545abd8dd01c3d62353bfcea71db580b51d22bd9" + integrity sha1-VFq9jdAcPWI1O/zqcdtYC1HSK9k= + dependencies: + ansi-styles "^3.0.0" + cardinal "^1.0.0" + cli-table "^0.3.1" + lodash.merge "^4.6.0" + markdown-it "^8.3.1" + +markdown-it@^8.3.1: + version "8.4.2" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54" + integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ== + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +markdown-it@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-9.1.0.tgz#df9601c168568704d554b1fff9af0c5b561168d9" + integrity sha512-xHKG4C8iPriyfu/jc2hsCC045fKrMQ0VexX2F1FGYiRxDxqMB2aAhF8WauJ3fltn2kb90moGBkiiEdooGIg55w== + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.5" + +matcher-collection@^1.0.0, matcher-collection@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-1.1.2.tgz#1076f506f10ca85897b53d14ef54f90a5c426838" + integrity sha512-YQ/teqaOIIfUHedRam08PB3NK7Mjct6BvzRnJmpGDm8uFXpNr1sbY4yuflI5JcEs6COpYA0FpRQhSDBf1tT95g== + dependencies: + minimatch "^3.0.2" + +matcher-collection@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/matcher-collection/-/matcher-collection-2.0.1.tgz#90be1a4cf58d6f2949864f65bb3b0f3e41303b29" + integrity sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ== + dependencies: + "@types/minimatch" "^3.0.3" + minimatch "^3.0.2" + +md5-hex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-2.0.0.tgz#d0588e9f1c74954492ecd24ac0ac6ce997d92e33" + integrity sha1-0FiOnxx0lUSS7NJKwKxs6ZfZLjM= + dependencies: + md5-o-matic "^0.1.1" + +md5-o-matic@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + integrity sha1-givM1l4RfFFPqxdrJZRdVBAKA8M= + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-streams@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/memory-streams/-/memory-streams-0.1.3.tgz#d9b0017b4b87f1d92f55f2745c9caacb1dc93ceb" + integrity sha512-qVQ/CjkMyMInPaaRMrwWNDvf6boRZXaT/DbQeMYcCWuXPEBf1v8qChOc9OlEVQp2uOvRXa1Qu30fLmKhY6NipA== + dependencies: + readable-stream "~1.0.2" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge-trees@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-1.0.1.tgz#ccbe674569787f9def17fd46e6525f5700bbd23e" + integrity sha1-zL5nRWl4f53vF/1G5lJfVwC70j4= + dependencies: + can-symlink "^1.0.0" + fs-tree-diff "^0.5.4" + heimdalljs "^0.2.1" + heimdalljs-logger "^0.1.7" + rimraf "^2.4.3" + symlink-or-copy "^1.0.0" + +merge-trees@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-trees/-/merge-trees-2.0.0.tgz#a560d796e566c5d9b2c40472a2967cca48d85161" + integrity sha512-5xBbmqYBalWqmhYm51XlohhkmVOua3VAUrrWh8t9iOkaLpS6ifqm/UVuUjQCeDVJ9Vx3g2l6ihfkbLSTeKsHbw== + dependencies: + fs-updater "^1.0.4" + heimdalljs "^0.2.5" + +merge2@^1.2.3, merge2@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" + integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.44.0, "mime-db@>= 1.43.0 < 2": + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.26, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.1.tgz#827ba4e7593464e7c221e8c5bed930904ee2c455" + integrity sha512-GY8fANSrTMfBVfInqJAY41QkOM+upUTytK1jZ0c8+3HdHrJxBJ3rF5i9moClXTE8uUSnUo8cAsCoxDXvSY4DHg== + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minipass@^2.2.0, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.0: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mktemp@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" + integrity sha1-bQUVYRyKjITkhKogABKbmOmB/ws= + +morgan@^1.9.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" + +mout@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/mout/-/mout-1.2.2.tgz#c9b718a499806a0632cede178e80f436259e777d" + integrity sha512-w0OUxFEla6z3d7sVpMZGBCpQvYh8PHS1wZ6Wu9GNKHMpAHWJ0if0LsQZh3DlOqw55HlhJEOMLpFnwtxp99Y5GA== + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +mustache@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-3.2.1.tgz#89e78a9d207d78f2799b1e95764a25bf71a28322" + integrity sha512-RERvMFdLpaFfSRIEe632yDm5nsd0SDKn8hGmcUwswnyiE5mtdZLDybtHAz6hjJhawokF0hXvGLtx9mrQfm6FkA== + +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" + integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nan@^2.12.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +needle@^2.2.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.1.tgz#14af48732463d7475696f937626b1b993247a56a" + integrity sha512-x/gi6ijr4B7fwl6WYL9FwlCvRQKGlUNvnceho8wxkwXqN8jvVmmmATTmZPRRG7b/yC1eode26C2HO9jl78Du9g== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.5.0, neo-async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" + integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== + dependencies: + lower-case "^2.0.1" + tslib "^1.10.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-libs-browser@^2.0.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-modules-path@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/node-modules-path/-/node-modules-path-1.0.2.tgz#e3acede9b7baf4bc336e3496b58e5b40d517056e" + integrity sha512-6Gbjq+d7uhkO7epaKi5DNgUJn7H0gEyA4Jg0Mo1uQOi3Rk50G83LtmhhFyw0LxnAFhtlspkiiw52ISP13qzcBg== + +node-notifier@^5.0.1: + version "5.4.3" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" + integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== + dependencies: + growly "^1.3.0" + is-wsl "^1.1.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" + +node-pre-gyp@*: + version "0.14.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz#9a0596533b877289bcad4e143982ca3d904ddc83" + integrity sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4.4.2" + +node-releases@^1.1.53: + version "1.1.53" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" + integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ== + +node-watch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/node-watch/-/node-watch-0.6.1.tgz#b9874111ce9f5841b1c7596120206c7b825be0e9" + integrity sha512-gwQiR7weFRV8mAtT0x0kXkZ18dfRLB45xH7q0hCOVQMLfLb2f1ZaSvR57q4/b/Vj6B0RwMNJYbvb69e1yM7qEA== + +nopt@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + +npm-bundled@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-package-arg@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" + integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== + dependencies: + hosted-git-info "^2.7.1" + osenv "^0.1.5" + semver "^5.6.0" + validate-npm-package-name "^3.0.0" + +npm-packlist@^1.1.6: + version "1.4.8" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-3.1.0.tgz#7f91be317f6a466efed3c9f2980ad8a4ee8b0fa5" + integrity sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg== + dependencies: + path-key "^3.0.0" + +npmlog@^4.0.0, npmlog@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.0.9: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@4.1.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-hash@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df" + integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA== + +object-inspect@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" + integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== + +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= + dependencies: + mimic-fn "^1.0.0" + +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +ora@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318" + integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg== + dependencies: + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-spinners "^2.0.0" + log-symbols "^2.2.0" + strip-ansi "^5.2.0" + wcwidth "^1.0.1" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.3, osenv@^0.1.4, osenv@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== + +p-defer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83" + integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-finally@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" + integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== + +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" + integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= + dependencies: + got "^6.7.1" + registry-auth-token "^3.0.1" + registry-url "^3.0.3" + semver "^5.1.0" + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0: + version "5.1.5" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parse5@5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" + integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@1.0.1, path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-posix@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-posix/-/path-posix-1.0.0.tgz#06b26113f56beab042545a23bfa88003ccac260f" + integrity sha1-BrJhE/Vr6rBCVFojv6iAA8ysJg8= + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= + dependencies: + path-root-regex "^0.1.0" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.0.17" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + +pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= + dependencies: + find-up "^2.1.0" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + +portfinder@^1.0.25: + version "1.0.25" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.25.tgz#254fd337ffba869f4b9d37edc298059cb4d35eca" + integrity sha512-6ElJnHBbxVA1XSLgBp7G1FiCkQdlqGzuF7DswL5tcea+E8UpuvPU7beVAjjRwCioTS9ZluNbu+ZyRvgTsmqEBg== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.1" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +printf@^0.5.1: + version "0.5.3" + resolved "https://registry.yarnpkg.com/printf/-/printf-0.5.3.tgz#8b7eec278d886833312238b2bf42b2b6f250880a" + integrity sha512-t3lYN6vPU5PZXDiEZZqoyXvN8wCsBfi8gPoxTKo2e5hhV673t/KUh+mfO8P8lCOCDC/BWcOGIxKyebxc5FuqLA== + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process-relative-require@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/process-relative-require/-/process-relative-require-1.0.0.tgz#1590dfcf5b8f2983ba53e398446b68240b4cc68a" + integrity sha1-FZDfz1uPKYO6U+OYRGtoJAtMxoo= + dependencies: + node-modules-path "^1.0.0" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +promise-map-series@^0.2.1, promise-map-series@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/promise-map-series/-/promise-map-series-0.2.3.tgz#c2d377afc93253f6bd03dbb77755eb88ab20a847" + integrity sha1-wtN3r8kyU/a9A9u3d1XriKsgqEc= + dependencies: + rsvp "^3.0.14" + +promise.prototype.finally@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067" + integrity sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.0" + function-bind "^1.1.1" + +proxy-addr@~2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== + dependencies: + forwarded "~0.1.2" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +qs@^6.4.0: + version "6.9.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e" + integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +quick-temp@^0.1.2, quick-temp@^0.1.3, quick-temp@^0.1.5, quick-temp@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/quick-temp/-/quick-temp-0.1.8.tgz#bab02a242ab8fb0dd758a3c9776b32f9a5d94408" + integrity sha1-urAqJCq4+w3XWKPJd2sy+aXZRAg= + dependencies: + mktemp "~0.4.0" + rimraf "^2.5.4" + underscore.string "~3.3.4" + +qunit-dom@^0.9.2: + version "0.9.2" + resolved "https://registry.yarnpkg.com/qunit-dom/-/qunit-dom-0.9.2.tgz#cc7bb777e4f5faa749eca843f54e199755df8473" + integrity sha512-BPf7OZjhXo9ekgsViNjQVS9BWkm2yQsPvBoy0juvt5nOFlcBVVwHSYsgpsJOunWkI1IgA3eStAC9mQx3Zw734g== + dependencies: + broccoli-funnel "^2.0.2" + broccoli-merge-trees "^3.0.1" + +qunit@^2.9.3: + version "2.9.3" + resolved "https://registry.yarnpkg.com/qunit/-/qunit-2.9.3.tgz#9522a088e76f0782f70a45db92f2fd14db311bcc" + integrity sha512-RH4VYSaVsNRDthMFFboTJAJ8q4kJM5LvOqWponKUYPEAeOcmc/YFV1QsZ7ikknA3TjqliWFJYEV63vvVXaALmQ== + dependencies: + commander "2.12.2" + js-reporters "1.2.1" + minimatch "3.0.4" + node-watch "0.6.1" + resolve "1.9.0" + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= + dependencies: + bytes "1" + string_decoder "0.10" + +rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +"readable-stream@2 || 3": + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~1.0.2: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +recast@^0.18.1: + version "0.18.10" + resolved "https://registry.yarnpkg.com/recast/-/recast-0.18.10.tgz#605ebbe621511eb89b6356a7e224bff66ed91478" + integrity sha512-XNvYvkfdAN9QewbrxeTOjgINkdY/odTgTS56ZNEWL9Ml0weT4T3sFtvnTuF+Gxyu46ANcRm1ntrF6F5LAJPAaQ== + dependencies: + ast-types "0.13.3" + esprima "~4.0.0" + private "^0.1.8" + source-map "~0.6.1" + +redeyed@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-1.0.1.tgz#e96c193b40c0816b00aec842698e61185e55498a" + integrity sha1-6WwZO0DAgWsArshCaY5hGF5VSYo= + dependencies: + esprima "~3.0.0" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.2.1, regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + integrity sha1-M2w+/BIgrc7dosn6tntaeVWjNlg= + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + +regenerator-runtime@^0.9.5: + version "0.9.6" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz#d33eb95d0d2001a4be39659707c51b0cb71ce029" + integrity sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck= + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regenerator-transform@^0.14.2: + version "0.14.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" + integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== + dependencies: + "@babel/runtime" "^7.8.4" + private "^0.1.8" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpp@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" + integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== + +regexpp@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA= + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +registry-auth-token@^3.0.1: + version "3.4.0" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" + integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A== + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + +registry-url@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= + dependencies: + rc "^1.0.1" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc= + +regjsgen@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw= + dependencies: + jsesc "~0.5.0" + +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + +remote-git-tags@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remote-git-tags/-/remote-git-tags-2.0.0.tgz#1152f39cf8b5268ae0e4307636ef741ec341664c" + integrity sha1-EVLznPi1Jorg5DB2Nu90HsNBZkw= + dependencies: + git-fetch-pack "^0.1.1" + git-transport-protocol "^0.1.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +request-promise-core@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" + integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== + dependencies: + lodash "^4.17.15" + +request-promise-native@^1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" + integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== + dependencies: + request-promise-core "1.1.3" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +reselect@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-3.0.1.tgz#efdaa98ea7451324d092b2b2163a6a1d7a9a2147" + integrity sha1-79qpjqdFEyTQkrKyFjpqHXqaIUc= + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-package-path@^1.0.11, resolve-package-path@^1.2.2, resolve-package-path@^1.2.6, resolve-package-path@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-1.2.7.tgz#2a7bc37ad96865e239330e3102c31322847e652e" + integrity sha512-fVEKHGeK85bGbVFuwO9o1aU0n3vqQGrezPc51JGu9UTXpFQfWq5qCeKxyaRUSvephs+06c5j5rPq/dzHGEo8+Q== + dependencies: + path-root "^0.1.1" + resolve "^1.10.0" + +resolve-package-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-2.0.0.tgz#7f258ab86ff074fff4ff8027a28f94d17d6fb1df" + integrity sha512-/CLuzodHO2wyyHTzls5Qr+EFeG6RcW4u6//gjYvUfcfyuplIX1SSccU+A5A9A78Gmezkl3NBkFAMxLbzTY9TJA== + dependencies: + path-root "^0.1.1" + resolve "^1.13.1" + +resolve-path@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" + integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= + dependencies: + http-errors "~1.6.2" + path-is-absolute "1.0.1" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.9.0.tgz#a14c6fdfa8f92a7df1d996cb7105fa744658ea06" + integrity sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ== + dependencies: + path-parse "^1.0.6" + +resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.0, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.3.3, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.7.1, resolve@^1.8.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@2.6.3, rimraf@~2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +rimraf@^2.2.8, rimraf@^2.3.4, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.1, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsvp@^3.0.14, rsvp@^3.0.17, rsvp@^3.0.18, rsvp@^3.0.21, rsvp@^3.0.6, rsvp@^3.1.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== + +rsvp@^4.6.1, rsvp@^4.7.0, rsvp@^4.8.1, rsvp@^4.8.2, rsvp@^4.8.4, rsvp@^4.8.5: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +rsvp@~3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.2.1.tgz#07cb4a5df25add9e826ebc67dcc9fd89db27d84a" + integrity sha1-B8tKXfJa3Z6Cbrxn3Mn9idsn2Eo= + +run-async@^2.2.0, run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +rxjs@^6.4.0, rxjs@^6.5.3: + version "6.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" + integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== + dependencies: + tslib "^1.9.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-json-parse@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.0, sane@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^3.1.3: + version "3.1.11" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" + integrity sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g== + dependencies: + xmlchars "^2.1.1" + +schema-utils@^0.4.4: + version "0.4.7" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.4.7.tgz#ba74f597d2be2ea880131746ee17d0a093c68187" + integrity sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ== + dependencies: + ajv "^6.1.0" + ajv-keywords "^3.1.0" + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.5: + version "2.6.6" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.6.tgz#299fe6bd4a3365dc23d99fd446caff8f1d6c330c" + integrity sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA== + dependencies: + ajv "^6.12.0" + ajv-keywords "^3.4.1" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" + integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +silent-error@^1.0.0, silent-error@^1.0.1, silent-error@^1.1.0, silent-error@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/silent-error/-/silent-error-1.1.1.tgz#f72af5b0d73682a2ba1778b7e32cd8aa7c2d8662" + integrity sha512-n4iEKyNcg4v6/jpb3c0/iyH2G1nzUNl7Gpqtn/mHIJK9S/q/7MCfoO4rwVOoO59qPFIc0hVHvMbiOJ0NdtxKKw== + dependencies: + debug "^2.2.0" + +simple-html-tokenizer@^0.5.9: + version "0.5.9" + resolved "https://registry.yarnpkg.com/simple-html-tokenizer/-/simple-html-tokenizer-0.5.9.tgz#1a83fe97f5a3e39b335fddf71cfe9b0263b581c2" + integrity sha512-w/3FEDN94r4JQ9WoYrIr8RqDIPZdyNkdpbK9glFady1CAEyD97XWCv8HFetQO21w81e7h7Nh59iYTyG1mUJftg== + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +snake-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.3.tgz#c598b822ab443fcbb145ae8a82c5e43526d5bbee" + integrity sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q== + dependencies: + dot-case "^3.0.3" + tslib "^1.10.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socket.io-adapter@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" + integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== + +socket.io-client@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4" + integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~4.1.0" + engine.io-client "~3.4.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io-parser@~3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.4.0.tgz#370bb4a151df2f77ce3345ff55a7072cc6e9565a" + integrity sha512-/G/VOI+3DBp0+DJKW4KesGnQkQPFmUCbA/oO2QGT6CWxU7hLGWqU3tyuzeSK/dqcyeHsQg1vTe9jiZI8GU9SCQ== + dependencies: + component-emitter "1.2.1" + debug "~4.1.0" + isarray "2.0.1" + +socket.io@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.3.0.tgz#cd762ed6a4faeca59bc1f3e243c0969311eb73fb" + integrity sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg== + dependencies: + debug "~4.1.0" + engine.io "~3.4.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.3.0" + socket.io-parser "~3.4.0" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + +sort-object-keys@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45" + integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg== + +sort-package-json@^1.23.1: + version "1.42.1" + resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.42.1.tgz#4085582dfe83c60951673de2d5e4ce09dd47bd4e" + integrity sha512-+JgZVjEQhJuJ57RCUcF3rzESYCW/n3vCLWdhqBdPkerEgRTj5teGdJrCcj772zT1VzewqWk616/4xuRyIffyqQ== + dependencies: + detect-indent "^6.0.0" + detect-newline "3.1.0" + git-hooks-list "1.0.3" + globby "11.0.0" + is-plain-obj "2.1.0" + sort-object-keys "^1.1.3" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map-support@~0.5.12: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" + integrity sha1-fsrxO1e80J2opAxdJp2zN5nUqvk= + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@0.4.x, source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.1.x: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + integrity sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y= + dependencies: + amdefine ">=0.0.4" + +sourcemap-validator@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/sourcemap-validator/-/sourcemap-validator-1.1.1.tgz#3d7d8a399ccab09c1fedc510d65436e25b1c386b" + integrity sha512-pq6y03Vs6HUaKo9bE0aLoksAcpeOo9HZd7I8pI6O480W/zxNZ9U32GfzgtPP0Pgc/K1JHna569nAbOk3X8/Qtw== + dependencies: + jsesc "~0.3.x" + lodash.foreach "^4.5.0" + lodash.template "^4.5.0" + source-map "~0.1.x" + +spawn-args@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/spawn-args/-/spawn-args-0.2.0.tgz#fb7d0bd1d70fd4316bd9e3dec389e65f9d6361bb" + integrity sha1-+30L0dcP1DFr2ePew4nmX51jYbs= + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@^1.0.3: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sri-toolbox@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/sri-toolbox/-/sri-toolbox-0.2.0.tgz#a7fea5c3fde55e675cf1c8c06f3ebb5c2935835e" + integrity sha1-p/6lw/3lXmdc8cjAbz67XCk1g14= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssri@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" + integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + dependencies: + figgy-pudding "^3.5.1" + +stagehand@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stagehand/-/stagehand-1.0.0.tgz#79515e2ad3a02c63f8720c7df9b6077ae14276d9" + integrity sha512-zrXl0QixAtSHFyN1iv04xOBgplbT4HgC8T7g+q8ESZbDNi5uZbMtxLukFVXPJ5Nl7zCYvYcrT3Mj24WYCH93hw== + dependencies: + debug "^4.1.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trimleft@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" + integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimstart "^1.0.0" + +string.prototype.trimright@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" + integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimend "^1.0.0" + +string.prototype.trimstart@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@0.10, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +styled_string@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/styled_string/-/styled_string-0.0.1.tgz#d22782bd81295459bc4f1df18c4bad8e94dd124a" + integrity sha1-0ieCvYEpVFm8Tx3xjEutjpTdEko= + +sum-up@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sum-up/-/sum-up-1.0.3.tgz#1c661f667057f63bcb7875aa1438bc162525156e" + integrity sha1-HGYfZnBX9jvLeHWqFDi8FiUlFW4= + dependencies: + chalk "^1.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +symlink-or-copy@^1.0.0, symlink-or-copy@^1.0.1, symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe" + integrity sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA== + +sync-disk-cache@^1.3.3: + version "1.3.4" + resolved "https://registry.yarnpkg.com/sync-disk-cache/-/sync-disk-cache-1.3.4.tgz#53a2c5a09d8f4bb53160bce182a456ad71574024" + integrity sha512-GlkGeM81GPPEKz/lH7QUTbvqLq7K/IUTuaKDSMulP9XQ42glqNJIN/RKgSOw4y8vxL1gOVvj+W7ruEO4s36eCw== + dependencies: + debug "^2.1.3" + heimdalljs "^0.2.3" + mkdirp "^0.5.0" + rimraf "^2.2.8" + username-sync "^1.0.2" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tap-parser@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-7.0.0.tgz#54db35302fda2c2ccc21954ad3be22b2cba42721" + integrity sha512-05G8/LrzqOOFvZhhAk32wsGiPZ1lfUrl+iV7+OkKgfofZxiceZWMHkKmow71YsyVQ8IvGBP2EjcIjE5gL4l5lA== + dependencies: + events-to-array "^1.0.1" + js-yaml "^3.2.7" + minipass "^2.2.0" + +tapable@^1.0.0, tapable@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar@^4.4.2: + version "4.4.13" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.13.tgz#43b364bc52888d555298637b10d60790254ab525" + integrity sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.8.6" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" + +temp@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.0.tgz#61391795a11bd9738d4c4d7f55f012cb8f55edaa" + integrity sha512-YfUhPQCJoNQE5N+FJQcdPz63O3x3sdT4Xju69Gj4iZe0lBKOtnAMi0SLj9xKhGkcGhsxThvTJ/usxtFPo438zQ== + dependencies: + rimraf "~2.6.2" + +terser-webpack-plugin@^1.1.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^2.1.2" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + +terser@^4.1.2, terser@^4.3.9: + version "4.6.12" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.12.tgz#44b98aef8703fdb09a3491bf79b43faffc5b4fee" + integrity sha512-fnIwuaKjFPANG6MAixC/k1TDtnl1YlPLUlLVIxxGZUn1gfUx2+l3/zGNB72wya+lgsb50QBi2tUV75RiODwnww== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +testem@^2.17.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/testem/-/testem-2.17.0.tgz#1cb4a2a90524a088803dfe52fbf197a6fd73c883" + integrity sha512-PLkIlT523w5rTJPWwR4TL1EiAEa941ECV7d4pMqsB0YdnH+sCTz0loWMKCUSdhR+VijveAZ6anE/JHehE7KqMQ== + dependencies: + backbone "^1.1.2" + bluebird "^3.4.6" + charm "^1.0.0" + commander "^2.6.0" + compression "^1.7.4" + consolidate "^0.15.1" + execa "^1.0.0" + express "^4.10.7" + fireworm "^0.7.0" + glob "^7.0.4" + http-proxy "^1.13.1" + js-yaml "^3.2.5" + lodash.assignin "^4.1.0" + lodash.castarray "^4.4.0" + lodash.clonedeep "^4.4.1" + lodash.find "^4.5.1" + lodash.uniqby "^4.7.0" + mkdirp "^0.5.1" + mustache "^3.0.0" + node-notifier "^5.0.1" + npmlog "^4.0.0" + printf "^0.5.1" + rimraf "^2.4.4" + socket.io "^2.1.0" + spawn-args "^0.2.0" + styled_string "0.0.1" + tap-parser "^7.0.0" + tmp "0.0.33" + xmldom "^0.1.19" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +"textextensions@1 || 2": + version "2.6.0" + resolved "https://registry.yarnpkg.com/textextensions/-/textextensions-2.6.0.tgz#d7e4ab13fe54e32e08873be40d51b74229b00fc4" + integrity sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ== + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" + integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== + dependencies: + readable-stream "2 || 3" + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +through@~2.2.0, through@~2.2.7: + version "2.2.7" + resolved "https://registry.yarnpkg.com/through/-/through-2.2.7.tgz#6e8e21200191d4eb6a99f6f010df46aa1c6eb2bd" + integrity sha1-bo4hIAGR1OtqmfbwEN9Gqhxusr0= + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + +timers-browserify@^2.0.4: + version "2.0.11" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" + integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== + dependencies: + setimmediate "^1.0.4" + +tiny-lr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== + dependencies: + body "^5.1.0" + debug "^3.1.0" + faye-websocket "~0.10.0" + livereload-js "^2.3.0" + object-assign "^4.1.0" + qs "^6.4.0" + +tmp@0.0.28: + version "0.0.28" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" + integrity sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA= + dependencies: + os-tmpdir "~1.0.1" + +tmp@0.0.33, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmp@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" + integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw== + dependencies: + rimraf "^2.6.3" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI= + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tough-cookie@^2.3.3, tough-cookie@^2.4.3, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + +tree-sync@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-1.4.0.tgz#314598d13abaf752547d9335b8f95d9a137100d6" + integrity sha512-YvYllqh3qrR5TAYZZTXdspnIhlKAYezPYw11ntmweoceu4VK+keN356phHRIIo1d+RDmLpHZrUlmxga2gc9kSQ== + dependencies: + debug "^2.2.0" + fs-tree-diff "^0.5.6" + mkdirp "^0.5.1" + quick-temp "^0.1.5" + walk-sync "^0.3.3" + +tree-sync@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tree-sync/-/tree-sync-2.0.0.tgz#e51456731d5ac93b92f9a1d58dd383f76f0f2f39" + integrity sha512-AzeJnbmJjGVfWMTJ0T152fv8NDTbQc9ERY4nEs7Lmxd94Xah2bUS56+CcoTh6FB8qn2KjBMjC0mLNc731aVBqw== + dependencies: + debug "^2.2.0" + fs-tree-diff "^0.5.6" + mkdirp "^0.5.1" + quick-temp "^0.1.5" + walk-sync "^0.3.3" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + +tslib@^1.10.0, tslib@^1.9.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" + integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typescript-memoize@^1.0.0-alpha.3: + version "1.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/typescript-memoize/-/typescript-memoize-1.0.0-alpha.3.tgz#699a5415f886694a8d6e2e5451bc28a39a6bc2f9" + integrity sha1-aZpUFfiGaUqNbi5UUbwoo5prwvk= + dependencies: + core-js "2.4.1" + +uc.micro@^1.0.1, uc.micro@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac" + integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA== + +uglify-js@^3.1.4: + version "3.9.1" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.9.1.tgz#a56a71c8caa2d36b5556cc1fd57df01ae3491539" + integrity sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA== + dependencies: + commander "~2.20.3" + +underscore.string@^3.2.2, underscore.string@~3.3.4: + version "3.3.5" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.5.tgz#fc2ad255b8bd309e239cbc5816fd23a9b7ea4023" + integrity sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg== + dependencies: + sprintf-js "^1.0.3" + util-deprecate "^1.0.2" + +underscore@>=1.8.3: + version "1.10.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.10.2.tgz#73d6aa3668f3188e4adb0f1943bd12cfd7efaaaf" + integrity sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg== + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unique-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +untildify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-2.1.0.tgz#17eb2807987f76952e9c0485fc311d06a826a2e0" + integrity sha1-F+soB5h/dpUunASF/DEdBqgmouA= + dependencies: + os-homedir "^1.0.0" + +unzip-response@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" + integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +username-sync@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/username-sync/-/username-sync-1.0.2.tgz#0a3697909fb7b5768d29e2921f573acfdd427592" + integrity sha512-ayNkOJdoNSGNDBE46Nkc+l6IXmeugbzahZLSMkwvgRWv5y5ZqNY2IrzcgmkR4z32sj1W3tM3TuTUMqkqBzO+RA== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +validate-npm-package-name@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= + dependencies: + builtins "^1.0.3" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +w3c-hr-time@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +walk-sync@^0.2.5: + version "0.2.7" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.2.7.tgz#b49be4ee6867657aeb736978b56a29d10fa39969" + integrity sha1-tJvk7mhnZXrrc2l4tWop0Q+jmWk= + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + +walk-sync@^0.3.0, walk-sync@^0.3.1, walk-sync@^0.3.2, walk-sync@^0.3.3: + version "0.3.4" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.4.tgz#cf78486cc567d3a96b5b2237c6108017a5ffb9a4" + integrity sha512-ttGcuHA/OBnN2pcM6johpYlEms7XpO5/fyKIr48541xXedan4roO8cS1Q2S/zbbjGH/BarYDAMeS2Mi9HE5Tig== + dependencies: + ensure-posix-path "^1.0.0" + matcher-collection "^1.0.0" + +walk-sync@^1.0.0, walk-sync@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-1.1.4.tgz#81049f3d8095479b49574cfa5f558d7a252b127d" + integrity sha512-nowc9thB/Jg0KW4TgxoRjLLYRPvl3DB/98S89r4ZcJqq2B0alNcKDh6pzLkBSkPMzRSMsJghJHQi79qw0YWEkA== + dependencies: + "@types/minimatch" "^3.0.3" + ensure-posix-path "^1.1.0" + matcher-collection "^1.1.1" + +walk-sync@^2.0.0, walk-sync@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-2.1.0.tgz#e214248e5f5cf497ddd87db5a2a02e47e29c6501" + integrity sha512-KpH9Xw64LNSx7/UI+3guRZvJWlDxVA4+KKb/4puRoVrG8GkvZRxnF3vhxdjgpoKJGL2TVg1OrtkXIE/VuGPLHQ== + dependencies: + "@types/minimatch" "^3.0.3" + ensure-posix-path "^1.1.0" + matcher-collection "^2.0.0" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +watch-detector@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/watch-detector/-/watch-detector-1.0.0.tgz#c7b722d8695fee9ab6071e0f38f258e6adb22609" + integrity sha512-siywMl3fXK30Tlpu/dUBHhlpxhQmHdguZ8OIb813eU9lrVmmsJa9k0+n1HtJ+7p3SzFCPq2XbmR3GUYpPC3TBA== + dependencies: + heimdalljs-logger "^0.1.10" + semver "^6.3.0" + silent-error "^1.1.1" + tmp "^0.1.0" + +watchpack@^1.5.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2" + integrity sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA== + dependencies: + chokidar "^2.1.8" + graceful-fs "^4.1.2" + neo-async "^2.5.0" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +webpack-sources@^1.3.0, webpack-sources@^1.4.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@~4.28: + version "4.28.4" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.28.4.tgz#1ddae6c89887d7efb752adf0c3cd32b9b07eacd0" + integrity sha512-NxjD61WsK/a3JIdwWjtIpimmvE6UrRi3yG54/74Hk9rwNj5FPkA4DJCf1z4ByDWLkvZhTZE+P3C/eh6UD5lDcw== + dependencies: + "@webassemblyjs/ast" "1.7.11" + "@webassemblyjs/helper-module-context" "1.7.11" + "@webassemblyjs/wasm-edit" "1.7.11" + "@webassemblyjs/wasm-parser" "1.7.11" + acorn "^5.6.2" + acorn-dynamic-import "^3.0.0" + ajv "^6.1.0" + ajv-keywords "^3.1.0" + chrome-trace-event "^1.0.0" + enhanced-resolve "^4.1.0" + eslint-scope "^4.0.0" + json-parse-better-errors "^1.0.2" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + micromatch "^3.1.8" + mkdirp "~0.5.0" + neo-async "^2.5.0" + node-libs-browser "^2.0.0" + schema-utils "^0.4.4" + tapable "^1.1.0" + terser-webpack-plugin "^1.1.0" + watchpack "^1.5.0" + webpack-sources "^1.3.0" + +websocket-driver@>=0.5.1: + version "0.7.3" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9" + integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg== + dependencies: + http-parser-js ">=0.4.0 <0.4.11" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" + integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg== + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +which@^1.2.14, which@^1.2.9, which@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wordwrap@^0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +workerpool@^2.3.0: + version "2.3.3" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-2.3.3.tgz#49a70089bd55e890d68cc836a19419451d7c81d7" + integrity sha512-L1ovlYHp6UObYqElXXpbd214GgbEKDED0d3sj7pRdFXjNkb2+un/AUcCkceHizO0IVI6SOGGncrcjozruCkRgA== + dependencies: + object-assign "4.1.1" + +workerpool@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-3.1.2.tgz#b34e79243647decb174b7481ab5b351dc565c426" + integrity sha512-WJFA0dGqIK7qj7xPTqciWBH5DlJQzoPjsANvc3Y4hNB0SScT+Emjvt0jPPkDBUjBNngX1q9hHgt1Gfwytu6pug== + dependencies: + "@babel/core" "^7.3.4" + object-assign "4.1.1" + rsvp "^4.8.4" + +workerpool@^5.0.1: + version "5.0.4" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-5.0.4.tgz#4f67cb70ff7550a27ab94de25b0b843cd92059a2" + integrity sha512-Sywova24Ow2NQ24JPB68bI89EdqMDjUXo4OpofK/QMD7C2ZVMloYBgQ5J3PChcBJHj2vspsmGx1/3nBKXtUkXQ== + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + +ws@^7.1.2: + version "7.2.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.5.tgz#abb1370d4626a5a9cd79d8de404aa18b3465d10d" + integrity sha512-C34cIU4+DB2vMyAbmEKossWq2ZQDr6QEyuuCzWrM9zfw1sGc0mYiJ0UnG9zzNykt49C2Fi34hvr2vssFQRS6EA== + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xmlchars@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xmldom@^0.1.19: + version "0.1.31" + resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" + integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yam@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/yam/-/yam-1.0.0.tgz#7f6c91dc0f5de75a031e6da6b3907c3d25ab0de5" + integrity sha512-Hv9xxHtsJ9228wNhk03xnlDReUuWVvHwM4rIbjdAXYvHLs17xjuyF50N6XXFMN6N0omBaqgOok/MCK3At9fTAg== + dependencies: + fs-extra "^4.0.2" + lodash.merge "^4.6.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= diff --git a/app/assets/javascripts/wizard-application.js b/app/assets/javascripts/wizard-application.js index 98de3df3c8..3b1e536366 100644 --- a/app/assets/javascripts/wizard-application.js +++ b/app/assets/javascripts/wizard-application.js @@ -1,5 +1,4 @@ -//= require ./discourse-common/utils/decorators -//= require_tree ./discourse-common +//= require_tree ./discourse-common/addon //= require i18n-patches //= require_tree ./select-kit //= require wizard/router diff --git a/lib/discourse_js_processor.rb b/lib/discourse_js_processor.rb index 015fb948a7..08d271e8bc 100644 --- a/lib/discourse_js_processor.rb +++ b/lib/discourse_js_processor.rb @@ -161,7 +161,7 @@ JS end # We need to strip the app subdirectory to replicate how ember-cli works. - path || logical_path&.gsub('app/', '') + path || logical_path&.gsub('app/', '')&.gsub('addon/', '') end end diff --git a/lib/freedom_patches/raw_handlebars.rb b/lib/freedom_patches/raw_handlebars.rb index 7a02f1209d..1242481f0e 100644 --- a/lib/freedom_patches/raw_handlebars.rb +++ b/lib/freedom_patches/raw_handlebars.rb @@ -11,7 +11,7 @@ class Barber::Precompiler def precompiler if !@precompiler - source = File.read("#{Rails.root}/app/assets/javascripts/discourse-common/lib/raw-handlebars.js") + source = File.read("#{Rails.root}/app/assets/javascripts/discourse-common/addon/lib/raw-handlebars.js") transpiler = DiscourseJsProcessor::Transpiler.new(skip_module: true) transpiled = transpiler.perform(source) diff --git a/package.json b/package.json index 8c25185e84..0a745f479b 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "main": "index.js", "repository": "git@github.com:discourse/discourse.git", "author": "Discourse", - "license": "MIT", + "license": "GPL-2.0-only", "dependencies": { "@fortawesome/fontawesome-free": "5.11.2", "@popperjs/core": "v2.0.6", From 9ec908950de03768f6394fa8088845113f2a2d0d Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 29 Apr 2020 12:54:22 -0400 Subject: [PATCH 0861/1830] DEV: Better error handling for s3 task --- lib/tasks/s3.rake | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/tasks/s3.rake b/lib/tasks/s3.rake index b913b0a0ee..1f0ee2e08d 100644 --- a/lib/tasks/s3.rake +++ b/lib/tasks/s3.rake @@ -71,7 +71,12 @@ def assets manifest.assets.each do |_, path| fullpath = (Rails.root + "public/assets/#{path}").to_s - content_type = MiniMime.lookup_by_filename(fullpath).content_type + mime = MiniMime.lookup_by_filename(fullpath) + if mime.nil? + STDERR.puts "ERROR: could not determine mime type for #{fullpath}" + end + + content_type = mime.content_type asset_path = "assets/#{path}" results << [fullpath, asset_path, content_type] From bc1f7bd6597a0586922485f8b1f70095c796b944 Mon Sep 17 00:00:00 2001 From: Joshua Rosenfeld Date: Wed, 29 Apr 2020 13:09:16 -0400 Subject: [PATCH 0862/1830] UX: Improve discobot random menion copy As suggested in https://meta.discourse.org/t/-/148336/10 --- plugins/discourse-narrative-bot/config/locales/server.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/discourse-narrative-bot/config/locales/server.en.yml b/plugins/discourse-narrative-bot/config/locales/server.en.yml index 86d081b5bb..38bad9ac85 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.en.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.en.yml @@ -127,7 +127,7 @@ en: I currently know how to do the following things: `@%{discobot_username} %{reset_trigger} {name-of-tutorial}` - > Starts an interactive tutorial. `{name-of-tutorial}` can be one of: `%{tracks}`. + > Starts an interactive tutorial just for you, in a personal message. `{name-of-tutorial}` can be one of: `%{tracks}`. bot_actions: |- `@%{discobot_username} %{dice_trigger} 2d6` > :game_die: 3, 6 From 08fbf199ad75dd049190e32fda70c0df2277c9a1 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 29 Apr 2020 13:13:44 -0400 Subject: [PATCH 0863/1830] FIX: S3 rake task can ignore yarn.lock --- lib/tasks/s3.rake | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/tasks/s3.rake b/lib/tasks/s3.rake index 1f0ee2e08d..7f6b0f79b9 100644 --- a/lib/tasks/s3.rake +++ b/lib/tasks/s3.rake @@ -71,27 +71,26 @@ def assets manifest.assets.each do |_, path| fullpath = (Rails.root + "public/assets/#{path}").to_s - mime = MiniMime.lookup_by_filename(fullpath) - if mime.nil? - STDERR.puts "ERROR: could not determine mime type for #{fullpath}" + # Ignore files we can't find the mime type of, like yarn.lock + if mime = MiniMime.lookup_by_filename(fullpath) + content_type = mime.content_type + + asset_path = "assets/#{path}" + results << [fullpath, asset_path, content_type] + + if File.exist?(fullpath + '.br') + results << [fullpath + '.br', brotli_s3_path(asset_path), content_type, 'br'] + end + + if File.exist?(fullpath + '.gz') + results << [fullpath + '.gz', gzip_s3_path(asset_path), content_type, 'gzip'] + end + + if File.exist?(fullpath + '.map') + results << [fullpath + '.map', asset_path + '.map', 'application/json'] + end end - content_type = mime.content_type - - asset_path = "assets/#{path}" - results << [fullpath, asset_path, content_type] - - if File.exist?(fullpath + '.br') - results << [fullpath + '.br', brotli_s3_path(asset_path), content_type, 'br'] - end - - if File.exist?(fullpath + '.gz') - results << [fullpath + '.gz', gzip_s3_path(asset_path), content_type, 'gzip'] - end - - if File.exist?(fullpath + '.map') - results << [fullpath + '.map', asset_path + '.map', 'application/json'] - end end results From a1b9150512cd0a1035259659122324dfd0fc4731 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 29 Apr 2020 19:37:21 +0200 Subject: [PATCH 0864/1830] DEV: adds a caret option to widget dropdown (#9588) --- .../discourse/app/widgets/widget-dropdown.js | 4 ++++ test/javascripts/widgets/widget-dropdown-test.js | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js b/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js index e882588d67..c063296e35 100644 --- a/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js +++ b/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js @@ -80,6 +80,9 @@ export const WidgetDropdownHeaderClass = { {{transformed.label}} + {{#if attrs.caret}} + {{d-icon "caret-down"}} + {{/if}} ` }; @@ -218,6 +221,7 @@ export const WidgetDropdownClass = { label=attrs.label translatedLabel=attrs.translatedLabel class=this.transformed.options.headerClass + caret=this.transformed.options.caret ) }} diff --git a/test/javascripts/widgets/widget-dropdown-test.js b/test/javascripts/widgets/widget-dropdown-test.js index 46625d7d7b..2bc7f94b26 100644 --- a/test/javascripts/widgets/widget-dropdown-test.js +++ b/test/javascripts/widgets/widget-dropdown-test.js @@ -302,3 +302,18 @@ widgetTest("bodyClass option", { assert.ok(body().classList.contains("and-yet-small")); } }); + +widgetTest("caret option", { + template: TEMPLATE, + + beforeEach() { + this.setProperties(DEFAULT_CONTENT); + this.set("options", { caret: true }); + }, + + test(assert) { + assert.ok( + exists("#my-dropdown .widget-dropdown-header .d-icon-caret-down") + ); + } +}); From 816a08cf5f576647227940c51a24e75df789a6d8 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 29 Apr 2020 19:42:50 +0200 Subject: [PATCH 0865/1830] UI: do not change widget dropdown separator background on hover (#9589) --- app/assets/stylesheets/common/components/widget-dropdown.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/common/components/widget-dropdown.scss b/app/assets/stylesheets/common/components/widget-dropdown.scss index b84b389bf9..8bf179d49f 100644 --- a/app/assets/stylesheets/common/components/widget-dropdown.scss +++ b/app/assets/stylesheets/common/components/widget-dropdown.scss @@ -38,6 +38,10 @@ padding: 0; background: $primary-low; margin: 0.25em 0; + + &:hover { + background: $primary-low; + } } &:hover { From 402194f313257021549d23514969bc69dd0274e5 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 29 Apr 2020 21:24:20 +0300 Subject: [PATCH 0866/1830] FIX: Enter selected link with 'o' on full page search Follow-up to 70012f20278430362649a26a28d3cb4b39449b64. --- app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js index dddc2f7374..b9b5ed22b4 100644 --- a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js +++ b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js @@ -54,7 +54,7 @@ const DEFAULT_BINDINGS = { ".latest-topic-list .latest-topic-list-item.selected div.main-link a.title", ".top-topic-list .latest-topic-list-item.selected div.main-link a.title", ".latest .featured-topic.selected a.title", - ".search-results .search-link" + ".search-results .fps-result.selected .search-link" ].join(", "), anonymous: true }, // open selected topic on latest or categories page From c85018cdfd1a36e8c33de25c44bf192d53e201c1 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 29 Apr 2020 21:40:21 +0300 Subject: [PATCH 0867/1830] Improve support for old browsers (#9515) * FEATURE: Improve crawler view * FIX: Make lazyYT crawler-friendly * DEV: Rename discourse-internet-explorer to discourse-unsupported-browser * DEV: Detect more unsupported browsers Follow-up to 4eebbd221239eaa3fc7e6f1bd6a9dcf0239b8444. * FIX: Hide browser update notice in print view --- .gitignore | 2 +- app/assets/javascripts/browser-detect.js | 9 +++ .../stylesheets/common/base/_topic-list.scss | 6 ++ .../common/base/crawler_layout.scss | 40 +++---------- app/helpers/topics_helper.rb | 4 +- app/views/layouts/crawler.html.erb | 12 ++-- app/views/list/list.erb | 56 ++++++++++++++---- app/views/topics/show.html.erb | 57 +++++++++---------- lib/plugin/metadata.rb | 2 +- .../config/locales/server.en.yml | 4 -- .../config/settings.yml | 6 -- .../discourse-unsupported-browser.js.es6} | 8 +-- .../assets/stylesheets/ie.scss | 0 .../config/locales/client.en.yml | 2 +- .../config/locales/server.en.yml | 4 ++ .../config/settings.yml | 6 ++ .../plugin.rb | 14 ++--- .../public/js/ie.js | 0 .../spec/middleware/anonymous_cache_spec.rb | 0 .../spec/requests/bootstrap_request_spec.rb | 16 +++--- plugins/lazy-yt/plugin.rb | 14 ++++- .../assets/javascripts/browser-update.js.erb | 3 +- 22 files changed, 151 insertions(+), 114 deletions(-) delete mode 100644 plugins/discourse-internet-explorer/config/locales/server.en.yml delete mode 100644 plugins/discourse-internet-explorer/config/settings.yml rename plugins/{discourse-internet-explorer/assets/javascripts/initializers/discourse-internet-explorer.js.es6 => discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6} (69%) rename plugins/{discourse-internet-explorer => discourse-unsupported-browser}/assets/stylesheets/ie.scss (100%) rename plugins/{discourse-internet-explorer => discourse-unsupported-browser}/config/locales/client.en.yml (78%) create mode 100644 plugins/discourse-unsupported-browser/config/locales/server.en.yml create mode 100644 plugins/discourse-unsupported-browser/config/settings.yml rename plugins/{discourse-internet-explorer => discourse-unsupported-browser}/plugin.rb (76%) rename plugins/{discourse-internet-explorer => discourse-unsupported-browser}/public/js/ie.js (100%) rename plugins/{discourse-internet-explorer => discourse-unsupported-browser}/spec/middleware/anonymous_cache_spec.rb (100%) rename plugins/{discourse-internet-explorer => discourse-unsupported-browser}/spec/requests/bootstrap_request_spec.rb (64%) diff --git a/.gitignore b/.gitignore index bc22f48bbd..97d1a6b930 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,7 @@ bootsnap-compile-cache/ !/plugins/discourse-narrative-bot !/plugins/discourse-presence !/plugins/discourse-local-dates -!/plugins/discourse-internet-explorer +!/plugins/discourse-unsupported-browser /plugins/*/auto_generated/ /spec/fixtures/plugins/my_plugin/auto_generated diff --git a/app/assets/javascripts/browser-detect.js b/app/assets/javascripts/browser-detect.js index bdbbc27b3e..c13298dbb4 100644 --- a/app/assets/javascripts/browser-detect.js +++ b/app/assets/javascripts/browser-detect.js @@ -1,3 +1,12 @@ if (!window.WeakMap || !window.Promise) { window.unsupportedBrowser = true; +} else { + // Some implementations of `WeakMap.prototype.has` do not accept false + // values and Ember's `isClassicDecorator` sometimes does that (it only + // checks for `null` and `undefined`). + try { + new WeakMap().has(0); + } catch (err) { + window.unsupportedBrowser = true; + } } diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index 5b9cff0076..01fc70a2bb 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -142,6 +142,12 @@ } } + .link-bottom-line { + .category-name { + margin-right: 12px; + } + } + .unread-indicator { &.read { display: none; diff --git a/app/assets/stylesheets/common/base/crawler_layout.scss b/app/assets/stylesheets/common/base/crawler_layout.scss index 8f42f9ae0b..c0ca931510 100644 --- a/app/assets/stylesheets/common/base/crawler_layout.scss +++ b/app/assets/stylesheets/common/base/crawler_layout.scss @@ -21,12 +21,6 @@ body.crawler { } } - .raw-topic-link { - display: block; - font-weight: bold; - margin-bottom: 0.25em; - } - .topic-list { margin-bottom: 1em; } @@ -34,6 +28,14 @@ body.crawler { footer { margin-top: 4em; } + + .category-title { + color: $primary; + } + + .discourse-tags { + color: $primary-medium; + } } .noscript-footer-nav { @@ -47,10 +49,7 @@ body.crawler { #noscript-footer { padding: 0 10px; -} - -.crawler-topic-title { - margin-top: 0.5em; + text-align: center; } .crawler-post { @@ -86,27 +85,6 @@ body.crawler { } } -#breadcrumbs { - margin-bottom: 0.5em; - font-size: $font-up-1; - > div { - margin-bottom: 0.15em; - } - .badge-category-bg { - background-color: $secondary-high; - } - .category-title { - color: $primary; - } -} - -.crawler-tags-list { - span { - display: block; - margin-bottom: 0.15em; - } -} - .crawler-linkback-list { margin-top: 1em; a { diff --git a/app/helpers/topics_helper.rb b/app/helpers/topics_helper.rb index 4f4a56b6e7..0020423621 100644 --- a/app/helpers/topics_helper.rb +++ b/app/helpers/topics_helper.rb @@ -12,9 +12,9 @@ module TopicsHelper category = topic.category if category && !category.uncategorized? - breadcrumb.push(url: category.url, name: category.name) + breadcrumb.push(url: category.url, name: category.name, color: category.color) while category = category.parent_category - breadcrumb.prepend(url: category.url, name: category.name) + breadcrumb.prepend(url: category.url, name: category.name, color: category.color) end end diff --git a/app/views/layouts/crawler.html.erb b/app/views/layouts/crawler.html.erb index e8fc43c023..b5a8345550 100644 --- a/app/views/layouts/crawler.html.erb +++ b/app/views/layouts/crawler.html.erb @@ -34,13 +34,13 @@ <%= yield %>
    <% content_for :head do %> diff --git a/app/views/topics/show.html.erb b/app/views/topics/show.html.erb index c5187769be..e9d3b96b9a 100644 --- a/app/views/topics/show.html.erb +++ b/app/views/topics/show.html.erb @@ -1,37 +1,36 @@ <% if @topic_view %> -

    - <%= render_topic_title(@topic_view.topic) %> -

    +
    +

    + <%= render_topic_title(@topic_view.topic) %> +

    - <% @breadcrumbs = categories_breadcrumb(@topic_view.topic) %> - <% if @breadcrumbs.present? %> - - <% end %> - - <% if SiteSetting.tagging_enabled %> - <% @tags = @topic_view.topic.tags %> - <% if @tags.present? %> -
    - <% @tags.each_with_index do |tag, i| %> -
    -
    + + <%= c[:name] %> + + + <% end %> + <% end %> + + <% if SiteSetting.tagging_enabled %> + <% @tags = @topic_view.topic.tags %> + <% if @tags.present? %> + '> +
    + <% @tags.each_with_index do |tag, i| %> + <% if i < @tags.size - 1 %>, <% end %> + <% end %>
    <% end %> -
    - <% end %> - <% end %> + <% end %> +
    +
    <%= server_plugin_outlet "topic_header" %> diff --git a/lib/plugin/metadata.rb b/lib/plugin/metadata.rb index cfdb98263f..04cb17a57e 100644 --- a/lib/plugin/metadata.rb +++ b/lib/plugin/metadata.rb @@ -74,7 +74,7 @@ class Plugin::Metadata "docker_manager", "lazy-yt", "poll", - "discourse-internet-explorer" + "discourse-unsupported-browser" ]) FIELDS ||= [:name, :about, :version, :authors, :url, :required_version, :transpile_js] diff --git a/plugins/discourse-internet-explorer/config/locales/server.en.yml b/plugins/discourse-internet-explorer/config/locales/server.en.yml deleted file mode 100644 index 03100823db..0000000000 --- a/plugins/discourse-internet-explorer/config/locales/server.en.yml +++ /dev/null @@ -1,4 +0,0 @@ -en: - site_settings: - discourse_internet_explorer_enabled: "Enable temporary Internet Explorer support. This plugin is an effort to maintain compatibility with older browsers and will be completely removed in the near future." - discourse_internet_explorer_deprecation_warning: "Show an Internet Explorer deprecation warning" diff --git a/plugins/discourse-internet-explorer/config/settings.yml b/plugins/discourse-internet-explorer/config/settings.yml deleted file mode 100644 index 582f929ac1..0000000000 --- a/plugins/discourse-internet-explorer/config/settings.yml +++ /dev/null @@ -1,6 +0,0 @@ -plugins: - discourse_internet_explorer_enabled: - default: true - discourse_internet_explorer_deprecation_warning: - default: true - client: true diff --git a/plugins/discourse-internet-explorer/assets/javascripts/initializers/discourse-internet-explorer.js.es6 b/plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 similarity index 69% rename from plugins/discourse-internet-explorer/assets/javascripts/initializers/discourse-internet-explorer.js.es6 rename to plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 index 96a52fbc19..a2c96deb82 100644 --- a/plugins/discourse-internet-explorer/assets/javascripts/initializers/discourse-internet-explorer.js.es6 +++ b/plugins/discourse-unsupported-browser/assets/javascripts/initializers/discourse-unsupported-browser.js.es6 @@ -2,12 +2,12 @@ import { withPluginApi } from "discourse/lib/plugin-api"; function initializeInternetExplorerDeprecation(api) { const siteSettings = api.container.lookup("site-settings:main"); - if (siteSettings.discourse_internet_explorer_deprecation_warning) { + if (siteSettings.browser_deprecation_warning) { const { isIE11 } = api.container.lookup("capabilities:main"); if (isIE11) { api.addGlobalNotice( - I18n.t("discourse_internet_explorer.deprecation_warning"), - "deprecate-internet-explorer", + I18n.t("discourse_unsupported_browser.deprecation_warning"), + "browser-deprecation-warning", { dismissable: true, dismissDuration: moment.duration(1, "week") } ); } @@ -15,7 +15,7 @@ function initializeInternetExplorerDeprecation(api) { } export default { - name: "discourse-internet-explorer", + name: "discourse-unsupported-browser", initialize() { withPluginApi("0.8.37", initializeInternetExplorerDeprecation); diff --git a/plugins/discourse-internet-explorer/assets/stylesheets/ie.scss b/plugins/discourse-unsupported-browser/assets/stylesheets/ie.scss similarity index 100% rename from plugins/discourse-internet-explorer/assets/stylesheets/ie.scss rename to plugins/discourse-unsupported-browser/assets/stylesheets/ie.scss diff --git a/plugins/discourse-internet-explorer/config/locales/client.en.yml b/plugins/discourse-unsupported-browser/config/locales/client.en.yml similarity index 78% rename from plugins/discourse-internet-explorer/config/locales/client.en.yml rename to plugins/discourse-unsupported-browser/config/locales/client.en.yml index 11d0a92ef9..fca8ed0b1e 100644 --- a/plugins/discourse-internet-explorer/config/locales/client.en.yml +++ b/plugins/discourse-unsupported-browser/config/locales/client.en.yml @@ -1,4 +1,4 @@ en: js: - discourse_internet_explorer: + discourse_unsupported_browser: deprecation_warning: This site will soon remove support for Internet Explorer 11 - please update your browser diff --git a/plugins/discourse-unsupported-browser/config/locales/server.en.yml b/plugins/discourse-unsupported-browser/config/locales/server.en.yml new file mode 100644 index 0000000000..aa0ed026bc --- /dev/null +++ b/plugins/discourse-unsupported-browser/config/locales/server.en.yml @@ -0,0 +1,4 @@ +en: + site_settings: + discourse_unsupported_browser_enabled: "Enable temporary support for old browsers. This plugin is an effort to maintain compatibility with older browsers and will be completely removed in the near future." + browser_deprecation_warning: "Show a warning to deprecated browsers" diff --git a/plugins/discourse-unsupported-browser/config/settings.yml b/plugins/discourse-unsupported-browser/config/settings.yml new file mode 100644 index 0000000000..6aa3ccf598 --- /dev/null +++ b/plugins/discourse-unsupported-browser/config/settings.yml @@ -0,0 +1,6 @@ +plugins: + discourse_unsupported_browser_enabled: + default: true + browser_deprecation_warning: + default: true + client: true diff --git a/plugins/discourse-internet-explorer/plugin.rb b/plugins/discourse-unsupported-browser/plugin.rb similarity index 76% rename from plugins/discourse-internet-explorer/plugin.rb rename to plugins/discourse-unsupported-browser/plugin.rb index 646dfff08a..c27d442090 100644 --- a/plugins/discourse-internet-explorer/plugin.rb +++ b/plugins/discourse-unsupported-browser/plugin.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true -# name: discourse-internet-explorer -# about: Attempts to provide backward support for internt explorer +# name: discourse-unsupported-browser +# about: Attempts to provide support for old and unsupported browser through polyfills # version: 1.0 # authors: Joffrey Jaffeux, David Taylor, Daniel Waterworth, Robin Ward -# url: https://github.com/discourse/discourse/tree/master/plugins/discourse-internet-explorer +# url: https://github.com/discourse/discourse/tree/master/plugins/discourse-unsupported-browser -enabled_site_setting :discourse_internet_explorer_enabled +enabled_site_setting :discourse_unsupported_browser_enabled hide_plugin if self.respond_to?(:hide_plugin) register_asset 'stylesheets/ie.scss' @@ -15,8 +15,8 @@ register_asset 'stylesheets/ie.scss' # been activated so it can be uploaded to CDNs. DiscourseEvent.on(:after_plugin_activation) do || polyfill_path = "#{Plugin::Instance.js_path}/#{self.directory_name}-optional.js" - FileUtils.cp("#{Rails.root}/public/plugins/discourse-internet-explorer/js/ie.js", polyfill_path) - Rails.configuration.assets.precompile << "plugins/discourse-internet-explorer-optional.js" + FileUtils.cp("#{Rails.root}/public/plugins/discourse-unsupported-browser/js/ie.js", polyfill_path) + Rails.configuration.assets.precompile << "plugins/discourse-unsupported-browser-optional.js" end after_initialize do @@ -42,7 +42,7 @@ after_initialize do # to be loaded before other files register_html_builder('server:before-script-load') do |controller| if BrowserDetection.browser(controller.request.env['HTTP_USER_AGENT']) == :ie - path = controller.helpers.script_asset_path('plugins/discourse-internet-explorer-optional') + path = controller.helpers.script_asset_path('plugins/discourse-unsupported-browser-optional') <<~JAVASCRIPT diff --git a/plugins/discourse-internet-explorer/public/js/ie.js b/plugins/discourse-unsupported-browser/public/js/ie.js similarity index 100% rename from plugins/discourse-internet-explorer/public/js/ie.js rename to plugins/discourse-unsupported-browser/public/js/ie.js diff --git a/plugins/discourse-internet-explorer/spec/middleware/anonymous_cache_spec.rb b/plugins/discourse-unsupported-browser/spec/middleware/anonymous_cache_spec.rb similarity index 100% rename from plugins/discourse-internet-explorer/spec/middleware/anonymous_cache_spec.rb rename to plugins/discourse-unsupported-browser/spec/middleware/anonymous_cache_spec.rb diff --git a/plugins/discourse-internet-explorer/spec/requests/bootstrap_request_spec.rb b/plugins/discourse-unsupported-browser/spec/requests/bootstrap_request_spec.rb similarity index 64% rename from plugins/discourse-internet-explorer/spec/requests/bootstrap_request_spec.rb rename to plugins/discourse-unsupported-browser/spec/requests/bootstrap_request_spec.rb index 34a6213afe..036e1ced50 100644 --- a/plugins/discourse-internet-explorer/spec/requests/bootstrap_request_spec.rb +++ b/plugins/discourse-unsupported-browser/spec/requests/bootstrap_request_spec.rb @@ -7,31 +7,31 @@ describe 'Bootstrapping the Discourse App' do context "when disabled" do before do - SiteSetting.discourse_internet_explorer_enabled = false + SiteSetting.discourse_unsupported_browser_enabled = false end it "does not include the IE stylesheet or Javascript" do get "/categories", headers: { "HTTP_USER_AGENT" => ie_agent } - expect(response.body).not_to match(/discourse-internet-explorer-optional.js/) - expect(response.body).not_to match(/stylesheets\/discourse-internet-explorer/) + expect(response.body).not_to match(/discourse-unsupported-browser-optional.js/) + expect(response.body).not_to match(/stylesheets\/discourse-unsupported-browser/) end end context "when enabled" do before do - SiteSetting.discourse_internet_explorer_enabled = true + SiteSetting.discourse_unsupported_browser_enabled = true end it "includes the IE js and css" do get "/categories", headers: { "HTTP_USER_AGENT" => ie_agent } - expect(response.body).to match(/discourse-internet-explorer-optional.js/) - expect(response.body).to match(/stylesheets\/discourse-internet-explorer/) + expect(response.body).to match(/discourse-unsupported-browser-optional.js/) + expect(response.body).to match(/stylesheets\/discourse-unsupported-browser/) end it "doesn't include IE stuff for non-IE browsers" do get "/categories", headers: { "HTTP_USER_AGENT" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36" } - expect(response.body).not_to match(/discourse-internet-explorer-optional.js/) - expect(response.body).not_to match(/stylesheets\/discourse-internet-explorer/) + expect(response.body).not_to match(/discourse-unsupported-browser-optional.js/) + expect(response.body).not_to match(/stylesheets\/discourse-unsupported-browser/) end end end diff --git a/plugins/lazy-yt/plugin.rb b/plugins/lazy-yt/plugin.rb index 02d143b371..9d0af49153 100644 --- a/plugins/lazy-yt/plugin.rb +++ b/plugins/lazy-yt/plugin.rb @@ -27,7 +27,19 @@ class Onebox::Engine::YoutubeOnebox # Put in the LazyYT div instead of the iframe escaped_title = ERB::Util.html_escape(video_title) - "
    " + + <<~EOF +
    + + + +
    + EOF else yt_onebox_to_html end diff --git a/vendor/assets/javascripts/browser-update.js.erb b/vendor/assets/javascripts/browser-update.js.erb index b32410b8e6..be54f3bc0f 100644 --- a/vendor/assets/javascripts/browser-update.js.erb +++ b/vendor/assets/javascripts/browser-update.js.erb @@ -18,6 +18,7 @@ var $buo = function() { return; } + document.getElementsByTagName('body')[0].classList.add("crawler"); var mainElement = document.getElementById("main"); var noscriptElements = document.getElementsByTagName("noscript"); // noscriptElements[0].innerHTML contains encoded HTML @@ -34,7 +35,7 @@ var $buo = function() { // create the notification div stylesheet var sheet = document.createElement("style"); - var style = ".buorg {position:absolute; z-index:111111; width:100%; top:0px; left:0px; background:#FDF2AB; text-align:left; font-family: sans-serif; color:#000; font-size: 14px;} .buorg div {padding: 8px;} .buorg a, .buorg a:visited {color:#E25600; text-decoration: underline;}"; + var style = ".buorg {position:absolute; z-index:111111; width:100%; top:0px; left:0px; background:#FDF2AB; text-align:left; font-family: sans-serif; color:#000; font-size: 14px;} .buorg div {padding: 8px;} .buorg a, .buorg a:visited {color:#E25600; text-decoration: underline;} @media print { .buorg { display: none !important; } }"; // insert the div and stylesheet into the DOM document.body.appendChild(div); // put it last in the DOM so Googlebot doesn't include it in search excerpts From e1dbc700b1152bc4e12a7f95d36f341d958f7967 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 29 Apr 2020 21:12:32 +0200 Subject: [PATCH 0868/1830] FIX: ensures widget dropdown doesn't overflow document (#9590) --- .../javascripts/discourse/app/widgets/widget-dropdown.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js b/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js index c063296e35..8fe72d3e33 100644 --- a/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js +++ b/app/assets/javascripts/discourse/app/widgets/widget-dropdown.js @@ -1,4 +1,5 @@ import { createWidget } from "discourse/widgets/widget"; +import { schedule } from "@ember/runloop"; import hbs from "discourse/widgets/hbs-compiler"; /* @@ -252,6 +253,9 @@ export const WidgetDropdownClass = { strategy: "fixed", placement: "bottom-start", modifiers: [ + { + name: "preventOverflow" + }, { name: "offset", options: { @@ -261,6 +265,10 @@ export const WidgetDropdownClass = { ] }); } + + schedule("afterRender", () => { + this._popper && this._popper.update(); + }); } }; From f697133b7dac400d4c1fc9ab662ee3265ad83a61 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 29 Apr 2020 16:14:35 -0400 Subject: [PATCH 0869/1830] DEV: Add Handlebars support to Ember CLI in discourse-common --- app/assets/javascripts/discourse-common/index.js | 9 ++++++++- app/assets/javascripts/discourse-common/package.json | 5 +++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse-common/index.js b/app/assets/javascripts/discourse-common/index.js index e8db57f915..7ad7fe9113 100644 --- a/app/assets/javascripts/discourse-common/index.js +++ b/app/assets/javascripts/discourse-common/index.js @@ -1,5 +1,12 @@ "use strict"; module.exports = { - name: require("./package").name + name: require("./package").name, + options: { + autoImport: { + alias: { + handlebars: "handlebars/dist/cjs/handlebars.js" + } + } + } }; diff --git a/app/assets/javascripts/discourse-common/package.json b/app/assets/javascripts/discourse-common/package.json index f56ec8cce4..bdd317efb4 100644 --- a/app/assets/javascripts/discourse-common/package.json +++ b/app/assets/javascripts/discourse-common/package.json @@ -18,14 +18,15 @@ }, "dependencies": { "ember-cli-babel": "^7.13.0", - "ember-cli-htmlbars": "^4.2.0" + "ember-cli-htmlbars": "^4.2.0", + "ember-auto-import": "^1.5.3", + "handlebars": "^4.7.0" }, "devDependencies": { "@ember/optional-features": "^1.1.0", "@glimmer/component": "^1.0.0", "babel-eslint": "^10.0.3", "broccoli-asset-rev": "^3.0.0", - "ember-auto-import": "^1.5.3", "ember-cli": "~3.15.2", "ember-cli-dependency-checker": "^3.2.0", "ember-cli-eslint": "^5.1.0", From 590830b931ec83f7ae4ccde3cf820a072d6c2d09 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Wed, 29 Apr 2020 23:15:39 +0300 Subject: [PATCH 0870/1830] HACK: Add dummy plugin folder On some installations, there may be a leftover symlink which uses the old plugin name: public/plugins/discourse-internet-explorer -> -> plugins/discourse-internet-explorer/public --- .gitignore | 1 + plugins/discourse-internet-explorer/public/.gitkeep | 0 2 files changed, 1 insertion(+) create mode 100644 plugins/discourse-internet-explorer/public/.gitkeep diff --git a/.gitignore b/.gitignore index 97d1a6b930..46e956c118 100644 --- a/.gitignore +++ b/.gitignore @@ -54,6 +54,7 @@ bootsnap-compile-cache/ !/plugins/discourse-narrative-bot !/plugins/discourse-presence !/plugins/discourse-local-dates +!/plugins/discourse-internet-explorer !/plugins/discourse-unsupported-browser /plugins/*/auto_generated/ diff --git a/plugins/discourse-internet-explorer/public/.gitkeep b/plugins/discourse-internet-explorer/public/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 From 8e4fea897e68e4b50e548f820dc1f1fdeeeb199d Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Wed, 29 Apr 2020 14:34:49 -0700 Subject: [PATCH 0871/1830] FIX: temporarily disable event listener for dismissing the first notification --- .../javascripts/discourse/app/components/site-header.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/site-header.js b/app/assets/javascripts/discourse/app/components/site-header.js index ec7084b815..a31c16f375 100644 --- a/app/assets/javascripts/discourse/app/components/site-header.js +++ b/app/assets/javascripts/discourse/app/components/site-header.js @@ -225,9 +225,10 @@ const SiteHeaderComponent = MountWidget.extend(Docking, PanEvents, { ); } }; - document.addEventListener("click", this._dismissFirstNotification, { - once: true - }); + // TODO: re-enable event listener + // document.addEventListener("click", this._dismissFirstNotification, { + // once: true + // }); } }, From 4f5ed8e781207f1122df9e80888273e51c74951f Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Thu, 30 Apr 2020 09:40:50 +1000 Subject: [PATCH 0872/1830] DEV: pry-nav was holding back on pry upgrades pry-nav is not yet supported on latest pry, this holds off on upgrading pry, which in turn holds off on upgrading deps Stripping pry-nav for now till it works with latest pry --- Gemfile | 1 - Gemfile.lock | 11 ++++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Gemfile b/Gemfile index 2b1fb36f22..39b714d5c7 100644 --- a/Gemfile +++ b/Gemfile @@ -173,7 +173,6 @@ group :test, :development do gem 'shoulda-matchers', require: false gem 'rspec-html-matchers' - gem 'pry-nav' gem 'byebug', require: ENV['RM_INFO'].nil?, platform: :mri gem 'rubocop', require: false gem "rubocop-discourse", require: false diff --git a/Gemfile.lock b/Gemfile.lock index f561205552..b059691d9d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -186,7 +186,7 @@ GEM memory_profiler (0.9.14) message_bus (3.1.0) rack (>= 1.1.3) - method_source (0.9.2) + method_source (1.0.0) mini_mime (1.0.2) mini_portile2 (2.4.0) mini_racer (0.2.10) @@ -257,11 +257,9 @@ GEM ast (~> 2.4.0) pg (1.2.3) progress (3.5.2) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - pry-nav (0.3.0) - pry (>= 0.9.10, < 0.13.0) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.4) @@ -506,7 +504,6 @@ DEPENDENCIES onebox parallel_tests pg - pry-nav pry-rails puma r2 From ca539fdccfd2361775342392d8b534ea18550e83 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Thu, 30 Apr 2020 10:09:22 +1000 Subject: [PATCH 0873/1830] FIX: Rename all instances of bookmarkWithReminder to just bookmark (#9579) * Rename all instances of bookmarkWithReminder and bookmark_with_reminder to just bookmark * Delete old bookmark code at the same time * Add migration to remove the bookmarkWithReminder post menu item if people have it set in site settings --- .../discourse/app/controllers/topic.js | 12 +----- .../discourse/app/lib/transform-post.js | 1 - .../javascripts/discourse/app/models/post.js | 30 +-------------- .../javascripts/discourse/app/models/topic.js | 15 ++------ .../discourse/app/templates/topic.hbs | 1 - .../discourse/app/widgets/post-menu.js | 38 +++---------------- app/serializers/post_serializer.rb | 17 ++------- config/site_settings.yml | 6 +-- ..._bookmarks_with_reminder_post_menu_item.rb | 28 ++++++++++++++ .../initializers/new-user-narrative.js.es6 | 6 +-- spec/serializers/post_serializer_spec.rb | 22 ++--------- test/javascripts/helpers/site-settings.js | 6 +-- test/javascripts/widgets/post-test.js | 7 +--- 13 files changed, 55 insertions(+), 134 deletions(-) create mode 100644 db/migrate/20200429045956_remove_bookmarks_with_reminder_post_menu_item.rb diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js index b934c13543..a49cbaf2e2 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic.js +++ b/app/assets/javascripts/discourse/app/controllers/topic.js @@ -652,7 +652,7 @@ export default Controller.extend(bufferedProperty("model"), { if (!this.currentUser) { return bootbox.alert(I18n.t("bookmarks.not_bookmarked")); } else if (post) { - return post.toggleBookmarkWithReminder(); + return post.toggleBookmark(); } else { return this.model.toggleBookmark().then(changedIds => { if (!changedIds) { @@ -665,16 +665,6 @@ export default Controller.extend(bufferedProperty("model"), { } }, - toggleBookmarkWithReminder(post) { - if (!this.currentUser) { - return bootbox.alert(I18n.t("bookmarks.not_bookmarked")); - } else if (post) { - return post.toggleBookmarkWithReminder(); - } else { - return this.model.toggleBookmarkWithReminder(); - } - }, - jumpToIndex(index) { this._jumpToIndex(index); }, diff --git a/app/assets/javascripts/discourse/app/lib/transform-post.js b/app/assets/javascripts/discourse/app/lib/transform-post.js index 986dc46c3c..60823f04fb 100644 --- a/app/assets/javascripts/discourse/app/lib/transform-post.js +++ b/app/assets/javascripts/discourse/app/lib/transform-post.js @@ -35,7 +35,6 @@ export function transformBasicPost(post) { username: post.username, avatar_template: post.avatar_template, bookmarked: post.bookmarked, - bookmarkedWithReminder: post.bookmarked_with_reminder, bookmarkReminderAt: post.bookmark_reminder_at, bookmarkReminderType: post.bookmark_reminder_type, yours: post.yours, diff --git a/app/assets/javascripts/discourse/app/models/post.js b/app/assets/javascripts/discourse/app/models/post.js index 550a1fbfac..e7cf6028e5 100644 --- a/app/assets/javascripts/discourse/app/models/post.js +++ b/app/assets/javascripts/discourse/app/models/post.js @@ -310,32 +310,6 @@ const Post = RestModel.extend({ }, toggleBookmark() { - let bookmarkedTopic; - - this.toggleProperty("bookmarked"); - - if (this.bookmarked && !this.get("topic.bookmarked")) { - this.set("topic.bookmarked", true); - bookmarkedTopic = true; - } - - // need to wait to hear back from server (stuff may not be loaded) - - return Post.updateBookmark(this.id, this.bookmarked) - .then(result => { - this.set("topic.bookmarked", result.topic_bookmarked); - this.appEvents.trigger("page:bookmark-post-toggled", this); - }) - .catch(error => { - this.toggleProperty("bookmarked"); - if (bookmarkedTopic) { - this.set("topic.bookmarked", false); - } - throw new Error(error); - }); - }, - - toggleBookmarkWithReminder() { return new Promise(resolve => { let controller = showModal("bookmark", { model: { @@ -357,7 +331,7 @@ const Post = RestModel.extend({ afterSave: savedData => { this.setProperties({ "topic.bookmarked": true, - bookmarked_with_reminder: true, + bookmarked: true, bookmark_reminder_at: savedData.reminderAt, bookmark_reminder_type: savedData.reminderType, bookmark_name: savedData.name, @@ -373,7 +347,7 @@ const Post = RestModel.extend({ bookmark_reminder_type: null, bookmark_name: null, bookmark_id: null, - bookmarked_with_reminder: false + bookmarked: false }); this.appEvents.trigger("page:bookmark-post-toggled", this); } diff --git a/app/assets/javascripts/discourse/app/models/topic.js b/app/assets/javascripts/discourse/app/models/topic.js index 46be3e7fee..00f8c8839f 100644 --- a/app/assets/javascripts/discourse/app/models/topic.js +++ b/app/assets/javascripts/discourse/app/models/topic.js @@ -400,7 +400,6 @@ const Topic = RestModel.extend({ afterTopicBookmarked(firstPost) { if (firstPost) { firstPost.set("bookmarked", true); - firstPost.set("bookmarked_with_reminder", true); this.set("bookmark_reminder_at", firstPost.bookmark_reminder_at); return [firstPost.id]; } @@ -439,7 +438,7 @@ const Topic = RestModel.extend({ return this.firstPost().then(firstPost => { const toggleBookmarkOnServer = () => { if (bookmark) { - return firstPost.toggleBookmarkWithReminder().then(() => { + return firstPost.toggleBookmark().then(() => { this.set("bookmarking", false); return this.afterTopicBookmarked(firstPost); }); @@ -449,7 +448,7 @@ const Topic = RestModel.extend({ this.toggleProperty("bookmarked"); this.set("bookmark_reminder_at", null); let clearedBookmarkProps = { - bookmarked_with_reminder: false, + bookmarked: false, bookmark_id: null, bookmark_name: null, bookmark_reminder_at: null @@ -458,10 +457,6 @@ const Topic = RestModel.extend({ const updated = []; posts.forEach(post => { if (post.bookmarked) { - post.set("bookmarked", false); - updated.push(post.id); - } - if (post.bookmarked_with_reminder) { post.setProperties(clearedBookmarkProps); updated.push(post.id); } @@ -477,11 +472,7 @@ const Topic = RestModel.extend({ const unbookmarkedPosts = []; if (!bookmark && posts) { - posts.forEach( - post => - (post.bookmarked || post.bookmarked_with_reminder) && - unbookmarkedPosts.push(post) - ); + posts.forEach(post => post.bookmarked && unbookmarkedPosts.push(post)); } return new Promise(resolve => { diff --git a/app/assets/javascripts/discourse/app/templates/topic.hbs b/app/assets/javascripts/discourse/app/templates/topic.hbs index 6fadf0b9b4..488970c10e 100644 --- a/app/assets/javascripts/discourse/app/templates/topic.hbs +++ b/app/assets/javascripts/discourse/app/templates/topic.hbs @@ -225,7 +225,6 @@ recoverPost=(action "recoverPost") expandHidden=(action "expandHidden") toggleBookmark=(action "toggleBookmark") - toggleBookmarkWithReminder=(action "toggleBookmarkWithReminder") togglePostType=(action "togglePostType") rebakePost=(action "rebakePost") changePostOwner=(action "changePostOwner") diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js index 98046266bd..73a786e0e3 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js @@ -287,31 +287,11 @@ registerButton("bookmark", attrs => { return; } - let className = "bookmark"; - - if (attrs.bookmarked) { - className += " bookmarked"; - } - - return { - id: attrs.bookmarked ? "unbookmark" : "bookmark", - action: "toggleBookmark", - title: attrs.bookmarked ? "bookmarks.created" : "bookmarks.not_bookmarked", - className, - icon: "bookmark" - }; -}); - -registerButton("bookmarkWithReminder", attrs => { - if (!attrs.canBookmark) { - return; - } - let classNames = ["bookmark", "with-reminder"]; let title = "bookmarks.not_bookmarked"; let titleOptions = {}; - if (attrs.bookmarkedWithReminder) { + if (attrs.bookmarked) { classNames.push("bookmarked"); if (attrs.bookmarkReminderAt) { @@ -331,8 +311,8 @@ registerButton("bookmarkWithReminder", attrs => { } return { - id: attrs.bookmarkedWithReminder ? "unbookmark" : "bookmark", - action: "toggleBookmarkWithReminder", + id: attrs.bookmarked ? "unbookmark" : "bookmark", + action: "toggleBookmark", title, titleOptions, className: classNames.join(" "), @@ -451,10 +431,7 @@ export default createWidget("post-menu", { const hiddenSetting = siteSettings.post_menu_hidden_items || ""; const hiddenButtons = hiddenSetting .split("|") - .filter(s => !attrs.bookmarked || s !== "bookmark") - .filter( - s => !attrs.bookmarkedWithReminder || s !== "bookmarkWithReminder" - ); + .filter(s => !attrs.bookmarked || s !== "bookmark"); if (currentUser && keyValueStore) { const likedPostId = keyValueStore.getInt("likedPostId"); @@ -468,12 +445,7 @@ export default createWidget("post-menu", { let visibleButtons = []; // filter menu items based on site settings - const orderedButtons = this.menuItems().filter(button => { - if (button === "bookmark") { - return false; - } - return true; - }); + const orderedButtons = this.menuItems(); // If the post is a wiki, make Edit more prominent if (attrs.wiki && attrs.canEdit) { diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb index 7bf90b98eb..ef39e37caa 100644 --- a/app/serializers/post_serializer.rb +++ b/app/serializers/post_serializer.rb @@ -49,7 +49,6 @@ class PostSerializer < BasicPostSerializer :user_title, :reply_to_user, :bookmarked, - :bookmarked_with_reminder, :bookmark_reminder_at, :bookmark_id, :bookmark_reminder_type, @@ -316,32 +315,24 @@ class PostSerializer < BasicPostSerializer true end - def bookmarked_with_reminder - true - end - def include_bookmarked? - (actions.present? && actions.keys.include?(PostActionType.types[:bookmark])) - end - - def include_bookmarked_with_reminder? post_bookmark.present? end def include_bookmark_reminder_at? - include_bookmarked_with_reminder? + include_bookmarked? end def include_bookmark_reminder_type? - include_bookmarked_with_reminder? + include_bookmarked? end def include_bookmark_name? - include_bookmarked_with_reminder? + include_bookmarked? end def include_bookmark_id? - include_bookmarked_with_reminder? + include_bookmarked? end def post_bookmark diff --git a/config/site_settings.yml b/config/site_settings.yml index ed4a4f1b81..2a0733c75a 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -189,7 +189,7 @@ basic: post_menu: client: true type: list - default: "read|like|share|flag|edit|bookmark|bookmarkWithReminder|delete|admin|reply" + default: "read|like|share|flag|edit|bookmark|delete|admin|reply" allow_any: false choices: - read @@ -201,11 +201,10 @@ basic: - bookmark - admin - reply - - bookmarkWithReminder post_menu_hidden_items: client: true type: list - default: "flag|bookmark|bookmarkWithReminder|edit|delete|admin" + default: "flag|bookmark|edit|delete|admin" allow_any: false choices: - like @@ -216,7 +215,6 @@ basic: - bookmark - admin - reply - - bookmarkWithReminder share_links: client: true type: list diff --git a/db/migrate/20200429045956_remove_bookmarks_with_reminder_post_menu_item.rb b/db/migrate/20200429045956_remove_bookmarks_with_reminder_post_menu_item.rb new file mode 100644 index 0000000000..ebbc5cf343 --- /dev/null +++ b/db/migrate/20200429045956_remove_bookmarks_with_reminder_post_menu_item.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +class RemoveBookmarksWithReminderPostMenuItem < ActiveRecord::Migration[6.0] + def up + execute <<~SQL + UPDATE site_settings SET value = REPLACE(value, '|bookmarkWithReminder|', '|') WHERE name = 'post_menu'; + SQL + execute <<~SQL + UPDATE site_settings SET value = REPLACE(value, 'bookmarkWithReminder|', '') WHERE name = 'post_menu'; + SQL + execute <<~SQL + UPDATE site_settings SET value = REPLACE(value, '|bookmarkWithReminder', '') WHERE name = 'post_menu'; + SQL + execute <<~SQL + UPDATE site_settings SET value = REPLACE(value, '|bookmarkWithReminder|', '|') WHERE name = 'post_menu_hidden'; + SQL + execute <<~SQL + UPDATE site_settings SET value = REPLACE(value, 'bookmarkWithReminder|', '') WHERE name = 'post_menu_hidden'; + SQL + execute <<~SQL + UPDATE site_settings SET value = REPLACE(value, '|bookmarkWithReminder', '') WHERE name = 'post_menu_hidden'; + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/plugins/discourse-narrative-bot/assets/javascripts/initializers/new-user-narrative.js.es6 b/plugins/discourse-narrative-bot/assets/javascripts/initializers/new-user-narrative.js.es6 index 35a3e09fc1..cc4c3d1bc1 100644 --- a/plugins/discourse-narrative-bot/assets/javascripts/initializers/new-user-narrative.js.es6 +++ b/plugins/discourse-narrative-bot/assets/javascripts/initializers/new-user-narrative.js.es6 @@ -14,19 +14,19 @@ function initialize(api) { }); api.modifyClass("model:post", { - toggleBookmarkWithReminder() { + toggleBookmark() { // if we are talking to discobot then any bookmarks should just // be created without reminder options, to streamline the new user // narrative. const discobotUserId = -2; - if (this.user_id === discobotUserId && !this.bookmarked_with_reminder) { + if (this.user_id === discobotUserId && !this.bookmarked) { return ajax("/bookmarks", { type: "POST", data: { post_id: this.id } }).then(response => { this.setProperties({ "topic.bookmarked": true, - bookmarked_with_reminder: true, + bookmarked: true, bookmark_id: response.id }); this.appEvents.trigger("post-stream:refresh", { id: this.id }); diff --git a/spec/serializers/post_serializer_spec.rb b/spec/serializers/post_serializer_spec.rb index 8791db56c6..91ca676ecd 100644 --- a/spec/serializers/post_serializer_spec.rb +++ b/spec/serializers/post_serializer_spec.rb @@ -235,28 +235,12 @@ describe PostSerializer do s end - context "when a user post action for the bookmark exists" do - before do - PostActionCreator.create(current_user, post, :bookmark) - end - - it "returns true" do - expect(serialized.as_json[:bookmarked]).to eq(true) - end - end - - context "when a user post action for the bookmark does not exist" do - it "does not return the bookmarked attribute" do - expect(serialized.as_json.key?(:bookmarked)).to eq(false) - end - end - context "when a Bookmark record exists for the user on the post" do let!(:bookmark) { Fabricate(:bookmark_next_business_day_reminder, user: current_user, post: post) } context "bookmarks with reminders" do it "returns true" do - expect(serialized.as_json[:bookmarked_with_reminder]).to eq(true) + expect(serialized.as_json[:bookmarked]).to eq(true) end it "returns the reminder_at for the bookmark" do @@ -266,8 +250,8 @@ describe PostSerializer do context "if topic_view is blank" do let(:topic_view) { nil } - it "does not return the bookmarked_with_reminder attribute" do - expect(serialized.as_json.key?(:bookmarked_with_reminder)).to eq(false) + it "does not return the bookmarked attribute" do + expect(serialized.as_json.key?(:bookmarked)).to eq(false) end end end diff --git a/test/javascripts/helpers/site-settings.js b/test/javascripts/helpers/site-settings.js index bf55374eb8..4d1181dbaf 100644 --- a/test/javascripts/helpers/site-settings.js +++ b/test/javascripts/helpers/site-settings.js @@ -13,10 +13,8 @@ Discourse.SiteSettingsOriginal = { ga_universal_tracking_code: "", ga_universal_domain_name: "auto", top_menu: "latest|new|unread|categories|top", - post_menu: - "like|share|flag|edit|bookmark|bookmarkWithReminder|delete|admin|reply", - post_menu_hidden_items: - "flag|bookmark|bookmarkWithReminder|edit|delete|admin", + post_menu: "like|share|flag|edit|bookmark|delete|admin|reply", + post_menu_hidden_items: "flag|bookmark|edit|delete|admin", share_links: "twitter|facebook|email", category_colors: "BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|27AA5B|B3B5B4|E45735", diff --git a/test/javascripts/widgets/post-test.js b/test/javascripts/widgets/post-test.js index b7131fc2a5..bc12234c31 100644 --- a/test/javascripts/widgets/post-test.js +++ b/test/javascripts/widgets/post-test.js @@ -532,15 +532,12 @@ widgetTest("can't bookmark", { widgetTest("bookmark", { template: - '{{mount-widget widget="post" args=args toggleBookmarkWithReminder=(action "toggleBookmarkWithReminder")}}', + '{{mount-widget widget="post" args=args toggleBookmark=(action "toggleBookmark")}}', beforeEach() { const args = { canBookmark: true }; this.set("args", args); - this.on( - "toggleBookmarkWithReminder", - () => (args.bookmarked_with_reminder = true) - ); + this.on("toggleBookmark", () => (args.bookmarked = true)); }, async test(assert) { assert.equal(find(".post-menu-area .bookmark").length, 1); From 310a7edee59109c64d1e8bd6584a717e3b7ba817 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Thu, 30 Apr 2020 11:22:20 +1000 Subject: [PATCH 0874/1830] DEV: remove unused columns from posts and topics avg_time on posts and topics have not been used in a year. This uses a re-runnable ddl transaction diasabled migration to drop the column, cause it touchs very high traffic table and may deadlock --- app/models/post.rb | 4 +++- app/models/topic.rb | 4 +++- ...10528_remove_avg_time_from_topics_posts.rb | 20 +++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb diff --git a/app/models/post.rb b/app/models/post.rb index acc6c540f2..5da5d16320 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -10,6 +10,9 @@ class Post < ActiveRecord::Base include HasCustomFields include LimitedEdit + # remove line Jan 2021 + self.ignored_columns = ["avg_time"] + cattr_accessor :plugin_permitted_create_params self.plugin_permitted_create_params = {} @@ -1107,7 +1110,6 @@ end # like_count :integer default(0), not null # incoming_link_count :integer default(0), not null # bookmark_count :integer default(0), not null -# avg_time :integer # score :float # reads :integer default(0), not null # post_type :integer default(1), not null diff --git a/app/models/topic.rb b/app/models/topic.rb index f1f17443ce..dbc6c44d15 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -10,6 +10,9 @@ class Topic < ActiveRecord::Base include LimitedEdit extend Forwardable + # remove line Jan 2021 + self.ignored_columns = ["avg_time"] + def_delegator :featured_users, :user_ids, :featured_user_ids def_delegator :featured_users, :choose, :feature_topic_users @@ -1567,7 +1570,6 @@ end # featured_user1_id :integer # featured_user2_id :integer # featured_user3_id :integer -# avg_time :integer # deleted_at :datetime # highest_post_number :integer default(0), not null # image_url :string diff --git a/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb b/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb new file mode 100644 index 0000000000..848f9e569f --- /dev/null +++ b/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +class RemoveAvgTimeFromTopicsPosts < ActiveRecord::Migration[6.0] + disable_ddl_transaction! + + def up + # this makes it re-runnable and also works if it was not created initially + execute <<~SQL + ALTER TABLE topics DROP COLUMN IF EXISTS avg_time CASCADE + SQL + + execute <<~SQL + ALTER TABLE posts DROP COLUMN IF EXISTS avg_time CASCADE + SQL + end + + def down + # do nothing re-runnable + end +end From 367cbf5d2b0e942608e9ed641d289c9fabcd88a5 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 30 Apr 2020 02:39:24 +0100 Subject: [PATCH 0875/1830] FEATURE: Allow user creation with admin api when local logins disabled (#9587) --- app/controllers/users_controller.rb | 2 +- spec/requests/users_controller_spec.rb | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 80583ad79b..2c0ca62876 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -477,7 +477,7 @@ class UsersController < ApplicationController authentication = UserAuthenticator.new(user, session) - if !authentication.has_authenticator? && !SiteSetting.enable_local_logins + if !authentication.has_authenticator? && !SiteSetting.enable_local_logins && !(current_user&.admin? && is_api?) return render body: nil, status: :forbidden end diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 9bb8992c70..5d09c1031f 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -654,6 +654,30 @@ describe UsersController do expect(User.find_by(username: @user.username).user_option.timezone).to eq("Australia/Brisbane") end end + + context "with local logins disabled" do + before do + SiteSetting.enable_local_logins = false + SiteSetting.enable_google_oauth2_logins = true + end + + it "blocks registration without authenticator information" do + post_user + expect(response.status).to eq(403) + end + + it "blocks with a regular api key" do + api_key = Fabricate(:api_key, user: user) + post "/u.json", params: post_user_params, headers: { HTTP_API_KEY: api_key.key } + expect(response.status).to eq(403) + end + + it "works with an admin api key" do + api_key = Fabricate(:api_key, user: Fabricate(:admin)) + post "/u.json", params: post_user_params, headers: { HTTP_API_KEY: api_key.key } + expect(response.status).to eq(200) + end + end end context 'when creating a non active user (unconfirmed email)' do From 3ac5df0546b80d930205bd40e6972c7a8377ca60 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 30 Apr 2020 10:50:26 +0800 Subject: [PATCH 0876/1830] UX: Add margin when displaying unlisted details in composer. --- app/assets/javascripts/discourse/app/templates/composer.hbs | 2 +- app/assets/stylesheets/common/base/compose.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/app/templates/composer.hbs b/app/assets/javascripts/discourse/app/templates/composer.hbs index 6f133154bd..c577fbc704 100644 --- a/app/assets/javascripts/discourse/app/templates/composer.hbs +++ b/app/assets/javascripts/discourse/app/templates/composer.hbs @@ -29,7 +29,7 @@ {{d-icon "far-eye-slash"}} {{/if}} {{#if model.unlistTopic}} - ({{i18n "composer.unlist"}}) + ({{i18n "composer.unlist"}}) {{/if}} {{#if model.noBump}} {{d-icon "anchor"}} diff --git a/app/assets/stylesheets/common/base/compose.scss b/app/assets/stylesheets/common/base/compose.scss index d67224cc61..4d02ef28c6 100644 --- a/app/assets/stylesheets/common/base/compose.scss +++ b/app/assets/stylesheets/common/base/compose.scss @@ -169,6 +169,10 @@ margin-right: 0.25em; } + .unlist { + margin-left: 0.25em; + } + .display-edit-reason { display: inline-flex; a { From 53e0d8fbab7d9b20235766a3ab862a8714927d93 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Thu, 30 Apr 2020 12:53:50 +1000 Subject: [PATCH 0877/1830] DEV: correct drop logic for columns in post table We need to recreate the badge_posts view each time we change column on the posts table. The p.* is auto expanded on view create, cascade should not have been used --- ...10528_remove_avg_time_from_topics_posts.rb | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb b/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb index 848f9e569f..6c150b2704 100644 --- a/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb +++ b/db/post_migrate/20200430010528_remove_avg_time_from_topics_posts.rb @@ -6,12 +6,33 @@ class RemoveAvgTimeFromTopicsPosts < ActiveRecord::Migration[6.0] def up # this makes it re-runnable and also works if it was not created initially execute <<~SQL - ALTER TABLE topics DROP COLUMN IF EXISTS avg_time CASCADE + ALTER TABLE topics DROP COLUMN IF EXISTS avg_time SQL - execute <<~SQL - ALTER TABLE posts DROP COLUMN IF EXISTS avg_time CASCADE - SQL + ActiveRecord::Base.transaction do + execute "DROP VIEW badge_posts" + + execute <<~SQL + ALTER TABLE posts DROP COLUMN IF EXISTS avg_time + SQL + + # we must recreate this view every time we amend posts + # p.* is auto expanded and persisted into the view definition + # at create time + execute <<~SQL + CREATE VIEW badge_posts AS + SELECT p.* + FROM posts p + JOIN topics t ON t.id = p.topic_id + JOIN categories c ON c.id = t.category_id + WHERE c.allow_badges AND + p.deleted_at IS NULL AND + t.deleted_at IS NULL AND + NOT c.read_restricted AND + t.visible AND + p.post_type IN (1,2,3) + SQL + end end def down From d6df92b0741d371c0db4b127cda26d6addf7dc28 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Thu, 30 Apr 2020 14:27:24 +1000 Subject: [PATCH 0878/1830] DEV: correct bad test Test was unlisting a topic and then checking for the unlist info in the whisper field --- test/javascripts/acceptance/composer-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/javascripts/acceptance/composer-test.js b/test/javascripts/acceptance/composer-test.js index 48237ff552..9520bd9d5c 100644 --- a/test/javascripts/acceptance/composer-test.js +++ b/test/javascripts/acceptance/composer-test.js @@ -524,7 +524,7 @@ QUnit.test( ); assert.ok( - find(".composer-fields .whisper") + find(".composer-fields .unlist") .text() .indexOf(I18n.t("composer.unlist")) > 0, "it sets the topic to unlisted" From 10f9f295dc5f66d1f1b01cc45ba32be4f8d3ee1d Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Thu, 30 Apr 2020 14:58:26 +1000 Subject: [PATCH 0879/1830] DEV: Add acceptance tests for bookmarks with reminders (#9592) --- .../discourse/app/components/tap-tile.js | 4 + .../app/templates/modal/bookmark.hbs | 7 +- test/javascripts/acceptance/bookmarks-test.js | 161 ++++++++++++++++++ test/javascripts/acceptance/topic-test.js | 17 +- test/javascripts/helpers/qunit-helpers.js | 5 + 5 files changed, 177 insertions(+), 17 deletions(-) create mode 100644 test/javascripts/acceptance/bookmarks-test.js diff --git a/app/assets/javascripts/discourse/app/components/tap-tile.js b/app/assets/javascripts/discourse/app/components/tap-tile.js index 3a5203573d..370415d826 100644 --- a/app/assets/javascripts/discourse/app/components/tap-tile.js +++ b/app/assets/javascripts/discourse/app/components/tap-tile.js @@ -2,6 +2,10 @@ import Component from "@ember/component"; import { propertyEqual } from "discourse/lib/computed"; export default Component.extend({ + init() { + this._super(...arguments); + this.set("elementId", `tap_tile_${this.tileId}`); + }, classNames: ["tap-tile"], classNameBindings: ["active"], click() { diff --git a/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs b/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs index 3a5075ebc9..d9e51fbbef 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs @@ -71,11 +71,12 @@ {{date-picker-future value=customReminderDate onSelect=(action (mut customReminderDate)) + id="bookmark-custom-date" }}
    {{d-icon "far-clock"}} - {{input placeholder="--:--" type="time" class="time-input" value=customReminderTime}} + {{input placeholder="--:--" id="bookmark-custom-time" type="time" class="time-input" value=customReminderTime}}
    {{/if}} @@ -98,11 +99,11 @@
    - {{d-button label="bookmarks.save" class="btn-primary" action=(action "saveAndClose")}} + {{d-button id="save-bookmark" label="bookmarks.save" class="btn-primary" action=(action "saveAndClose")}} {{d-modal-cancel close=(action "closeWithoutSavingBookmark")}} {{#if showDelete}}
    - {{d-button icon="trash" class="btn-danger" action=(action "delete")}} + {{d-button id="delete-bookmark" icon="trash" class="btn-danger" action=(action "delete")}}
    {{/if}}
    diff --git a/test/javascripts/acceptance/bookmarks-test.js b/test/javascripts/acceptance/bookmarks-test.js new file mode 100644 index 0000000000..2c2008f3e2 --- /dev/null +++ b/test/javascripts/acceptance/bookmarks-test.js @@ -0,0 +1,161 @@ +import { acceptance, loggedInUser } from "helpers/qunit-helpers"; +import pretender from "helpers/create-pretender"; + +acceptance("Bookmarking", { + loggedIn: true, + + beforeEach() {} +}); + +function mockSuccessfulBookmarkPost() { + pretender.post("/bookmarks", () => [ + 200, + { + "Content-Type": "application/json" + }, + { + id: 999, + success: "OK" + } + ]); +} + +async function openBookmarkModal() { + await click(".topic-post:first-child button.show-more-actions"); + return await click(".topic-post:first-child button.bookmark"); +} +async function openEditBookmarkModal() { + return await click(".topic-post:first-child button.bookmarked"); +} + +test("Bookmarks modal opening", async assert => { + await visit("/t/internationalization-localization/280"); + await openBookmarkModal(); + assert.ok(exists("#bookmark-reminder-modal"), "it shows the bookmark modal"); +}); + +test("Bookmarks modal selecting reminder type", async assert => { + await visit("/t/internationalization-localization/280"); + await openBookmarkModal(); + await click("#tap_tile_tomorrow"); + assert.ok(exists("#tap_tile_tomorrow.active"), "it selects tomorrow"); + await click("#tap_tile_start_of_next_business_week"); + assert.ok( + exists("#tap_tile_start_of_next_business_week.active"), + "it selects next monday" + ); + await click("#tap_tile_next_week"); + assert.ok(exists("#tap_tile_next_week.active"), "it selects next week"); + await click("#tap_tile_next_month"); + assert.ok(exists("#tap_tile_next_month.active"), "it selects next month"); + await click("#tap_tile_custom"); + assert.ok(exists("#tap_tile_custom.active"), "it selects custom"); + assert.ok(exists(".tap-tile-date-input"), "it shows the custom date input"); + assert.ok(exists(".tap-tile-time-input"), "it shows the custom time input"); +}); + +test("Saving a bookmark with a reminder", async assert => { + mockSuccessfulBookmarkPost(); + await visit("/t/internationalization-localization/280"); + await openBookmarkModal(); + await fillIn("input#bookmark-name", "Check this out later"); + await click("#tap_tile_tomorrow"); + await click("#save-bookmark"); + assert.ok( + exists(".topic-post:first-child button.bookmark.bookmarked"), + "it shows the bookmarked icon on the post" + ); + assert.ok( + exists( + ".topic-post:first-child button.bookmark.bookmarked > .d-icon-discourse-bookmark-clock" + ), + "it shows the bookmark clock icon because of the reminder" + ); +}); + +test("Saving a bookmark with no reminder or name", async assert => { + mockSuccessfulBookmarkPost(); + await visit("/t/internationalization-localization/280"); + await openBookmarkModal(); + await click("#save-bookmark"); + assert.ok( + exists(".topic-post:first-child button.bookmark.bookmarked"), + "it shows the bookmarked icon on the post" + ); + assert.not( + exists( + ".topic-post:first-child button.bookmark.bookmarked > .d-icon-discourse-bookmark-clock" + ), + "it shows the regular bookmark active icon" + ); +}); + +test("Deleting a bookmark with a reminder", async assert => { + pretender.delete("/bookmarks/999", () => [ + 200, + { + "Content-Type": "application/json" + }, + { + success: "OK", + topic_bookmarked: false + } + ]); + mockSuccessfulBookmarkPost(); + await visit("/t/internationalization-localization/280"); + await openBookmarkModal(); + await click("#tap_tile_tomorrow"); + await click("#save-bookmark"); + await openEditBookmarkModal(); + assert.ok(exists("#bookmark-reminder-modal"), "it shows the bookmark modal"); + await click("#delete-bookmark"); + assert.ok(exists(".bootbox.modal"), "it asks for delete confirmation"); + assert.ok( + find(".bootbox.modal") + .text() + .includes(I18n.t("bookmarks.confirm_delete")), + "it shows delete confirmation message" + ); + await click(".bootbox.modal .btn-primary"); + assert.not( + exists(".topic-post:first-child button.bookmark.bookmarked"), + "it no longer shows the bookmarked icon on the post after bookmark is deleted" + ); +}); + +test("Cancelling saving a bookmark", async assert => { + await visit("/t/internationalization-localization/280"); + await openBookmarkModal(); + await click(".d-modal-cancel"); + assert.not( + exists(".topic-post:first-child button.bookmark.bookmarked"), + "it does not show the bookmarked icon on the post because it is not saved" + ); +}); + +test("Editing a bookmark", async assert => { + mockSuccessfulBookmarkPost(); + await visit("/t/internationalization-localization/280"); + let now = moment.tz(loggedInUser().resolvedTimezone()); + let tomorrow = now.add(1, "day").format("YYYY-MM-DD"); + await openBookmarkModal(); + await fillIn("input#bookmark-name", "Test name"); + await click("#tap_tile_tomorrow"); + await click("#save-bookmark"); + await openEditBookmarkModal(); + assert.equal( + find("#bookmark-name").val(), + "Test name", + "it should prefill the bookmark name" + ); + assert.equal( + find("#bookmark-custom-date > input").val(), + tomorrow, + "it should prefill the bookmark date" + ); + assert.equal( + find("#bookmark-custom-time").val(), + "08:00", + "it should prefill the bookmark time" + ); +}); diff --git a/test/javascripts/acceptance/topic-test.js b/test/javascripts/acceptance/topic-test.js index 94f3165dc9..ab271369c3 100644 --- a/test/javascripts/acceptance/topic-test.js +++ b/test/javascripts/acceptance/topic-test.js @@ -248,9 +248,9 @@ QUnit.test("remove featured link", async assert => { "link to remove featured link" ); - await click('.title-wrapper .remove-featured-link'); - await click('.title-wrapper .submit-edit'); - assert.ok(!exists('.title-wrapper .topic-featured-link'), 'link is gone'); + await click(".title-wrapper .remove-featured-link"); + await click(".title-wrapper .submit-edit"); + assert.ok(!exists(".title-wrapper .topic-featured-link"), "link is gone"); }); QUnit.test("Converting to a public topic", async assert => { @@ -395,17 +395,6 @@ QUnit.test( } ); -acceptance("Topic + Post Bookmarks with Reminders", { - loggedIn: true -}); - -QUnit.test("Bookmarks Modal", async assert => { - await visit("/t/internationalization-localization/280"); - await click(".topic-post:first-child button.show-more-actions"); - await click(".topic-post:first-child button.bookmark"); - assert.ok(exists("#bookmark-reminder-modal"), "it shows the bookmark modal"); -}); - acceptance("Topic with title decorated", { loggedIn: true, beforeEach() { diff --git a/test/javascripts/helpers/qunit-helpers.js b/test/javascripts/helpers/qunit-helpers.js index e0621c294d..0bc9eaece8 100644 --- a/test/javascripts/helpers/qunit-helpers.js +++ b/test/javascripts/helpers/qunit-helpers.js @@ -36,6 +36,11 @@ export function logIn() { User.resetCurrent(currentUser()); } +// Note: Only use if `loggedIn: true` has been used in an acceptance test +export function loggedInUser() { + return User.current(); +} + const Plugin = $.fn.modal; const Modal = Plugin.Constructor; From 02ef88052d6136ad4d8a003e1e4d5edb50ac15c0 Mon Sep 17 00:00:00 2001 From: Andrew Schleifer Date: Thu, 30 Apr 2020 14:15:08 +0800 Subject: [PATCH 0880/1830] DEV: take out more trash (icons) folloup to f75581090615db661b65bc630284d9dbb66b3f49 --- .../javascripts/discourse/app/templates/modal/bookmark.hbs | 2 +- .../javascripts/discourse/app/templates/modal/publish-page.hbs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs b/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs index d9e51fbbef..821ffe1976 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/bookmark.hbs @@ -103,7 +103,7 @@ {{d-modal-cancel close=(action "closeWithoutSavingBookmark")}} {{#if showDelete}}
    - {{d-button id="delete-bookmark" icon="trash" class="btn-danger" action=(action "delete")}} + {{d-button id="delete-bookmark" icon="trash-alt" class="btn-danger" action=(action "delete")}}
    {{/if}}
    diff --git a/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs b/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs index 07c3640ddd..712682fe74 100644 --- a/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs +++ b/app/assets/javascripts/discourse/app/templates/modal/publish-page.hbs @@ -44,7 +44,7 @@ {{d-button label="topic.publish_page.unpublish" - icon="trash" + icon="trash-alt" class="btn-danger" isLoading=unpublishing action=(action "unpublish") }} From d0d5a138c3b6d7755056336508b69a524975b364 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Thu, 30 Apr 2020 16:48:34 +1000 Subject: [PATCH 0881/1830] DEV: stop freezing frozen strings We have the `# frozen_string_literal: true` comment on all our files. This means all string literals are frozen. There is no need to call #freeze on any literals. For files with `# frozen_string_literal: true` ``` puts %w{a b}[0].frozen? => true puts "hi".frozen? => true puts "a #{1} b".frozen? => true puts ("a " + "b").frozen? => false puts (-("a " + "b")).frozen? => true ``` For more details see: https://samsaffron.com/archive/2018/02/16/reducing-string-duplication-in-ruby --- app/controllers/categories_controller.rb | 14 +++++++------- app/controllers/webhooks_controller.rb | 16 ++++++++-------- app/helpers/application_helper.rb | 4 ++-- app/jobs/regular/bulk_user_title_update.rb | 4 ++-- app/jobs/regular/emit_web_hook_event.rb | 4 ++-- .../scheduled/bookmark_reminder_notifications.rb | 2 +- .../scheduled/pending_queued_posts_reminder.rb | 2 +- .../scheduled/pending_reviewables_reminder.rb | 2 +- app/jobs/scheduled/pending_users_reminder.rb | 2 +- app/jobs/scheduled/poll_mailbox.rb | 4 ++-- app/models/category_featured_topic.rb | 2 +- app/models/category_list.rb | 2 +- app/models/concerns/category_hashtag.rb | 2 +- app/models/emoji.rb | 6 +++--- app/models/topic.rb | 2 +- app/models/topic_link.rb | 2 +- app/models/topic_tracking_state.rb | 6 +++--- app/models/upload.rb | 2 +- app/models/user.rb | 4 ++-- .../incoming_email_details_serializer.rb | 2 +- app/services/badge_granter.rb | 2 +- config/initializers/100-silence_logger.rb | 12 ++++++------ .../postgresql_fallback_adapter.rb | 2 +- lib/badge_posts_view_manager.rb | 2 +- lib/base62.rb | 2 +- lib/bookmark_reminder_notification_handler.rb | 2 +- lib/discourse.rb | 4 ++-- lib/discourse_redis.rb | 8 ++++---- lib/email/message_builder.rb | 2 +- lib/email/styles.rb | 4 ++-- lib/file_store/base_store.rb | 4 ++-- lib/html_prettify.rb | 6 +++--- lib/migration/base_dropper.rb | 2 +- lib/plain_text_to_markdown.rb | 2 +- lib/post_creator.rb | 2 +- lib/pretty_text.rb | 2 +- lib/quote_comparer.rb | 2 +- lib/s3_helper.rb | 4 ++-- lib/site_setting_extension.rb | 2 +- lib/topic_query.rb | 2 +- lib/twitter_api.rb | 2 +- lib/validators/censored_words_validator.rb | 2 +- lib/validators/regex_setting_validator.rb | 2 +- lib/webauthn.rb | 4 ++-- script/bulk_import/base.rb | 6 +++--- script/bulk_import/discourse_merger.rb | 2 +- script/bulk_import/vanilla.rb | 8 ++++---- script/bulk_import/vbulletin.rb | 2 +- script/import_scripts/mbox/support/indexer.rb | 2 +- spec/components/discourse_tagging_spec.rb | 2 +- spec/support/webauthn_integration_helpers.rb | 12 ++++++------ 51 files changed, 98 insertions(+), 98 deletions(-) diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 8481531b64..acb39e7cab 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -24,7 +24,7 @@ class CategoriesController < ApplicationController parent_category = Category.find_by_slug(params[:parent_category_id]) || Category.find_by(id: params[:parent_category_id].to_i) category_options = { - is_homepage: current_homepage == "categories".freeze, + is_homepage: current_homepage == "categories", parent_category_id: params[:parent_category_id], include_topics: include_topics(parent_category) } @@ -53,10 +53,10 @@ class CategoriesController < ApplicationController no_definitions: true } - if style == "categories_and_latest_topics".freeze + if style == "categories_and_latest_topics" @topic_list = TopicQuery.new(current_user, topic_options).list_latest @topic_list.more_topics_url = url_for(public_send("latest_path")) - elsif style == "categories_and_top_topics".freeze + elsif style == "categories_and_top_topics" @topic_list = TopicQuery.new(nil, topic_options).list_top_for(SiteSetting.top_page_default_timeframe.to_sym) @topic_list.more_topics_url = url_for(public_send("top_path")) end @@ -245,7 +245,7 @@ class CategoriesController < ApplicationController discourse_expires_in 1.minute category_options = { - is_homepage: current_homepage == "categories".freeze, + is_homepage: current_homepage == "categories", parent_category_id: params[:parent_category_id], include_topics: false } @@ -354,8 +354,8 @@ class CategoriesController < ApplicationController view_context.mobile_view? || params[:include_topics] || (parent_category && parent_category.subcategory_list_includes_topics?) || - style == "categories_with_featured_topics".freeze || - style == "categories_boxes_with_topics".freeze || - style == "categories_with_top_topics".freeze + style == "categories_with_featured_topics" || + style == "categories_boxes_with_topics" || + style == "categories_with_top_topics" end end diff --git a/app/controllers/webhooks_controller.rb b/app/controllers/webhooks_controller.rb index 320abe17fe..347ff52312 100644 --- a/app/controllers/webhooks_controller.rb +++ b/app/controllers/webhooks_controller.rb @@ -15,13 +15,13 @@ class WebhooksController < ActionController::Base events.each do |event| message_id = (event["smtp-id"] || "").tr("<>", "") to_address = event["email"] - if event["event"] == "bounce".freeze + if event["event"] == "bounce" if event["status"]["4."] process_bounce(message_id, to_address, SiteSetting.soft_bounce_score) else process_bounce(message_id, to_address, SiteSetting.hard_bounce_score) end - elsif event["event"] == "dropped".freeze + elsif event["event"] == "dropped" process_bounce(message_id, to_address, SiteSetting.hard_bounce_score) end end @@ -34,7 +34,7 @@ class WebhooksController < ActionController::Base events.each do |event| message_id = event["CustomID"] to_address = event["email"] - if event["event"] == "bounce".freeze + if event["event"] == "bounce" if event["hard_bounce"] process_bounce(message_id, to_address, SiteSetting.hard_bounce_score) else @@ -156,9 +156,9 @@ class WebhooksController < ActionController::Base # only handle soft bounces, because hard bounces are also handled # by the "dropped" event and we don't want to increase bounce score twice # for the same message - if event == "bounced".freeze && params["error"]["4."] + if event == "bounced" && params["error"]["4."] process_bounce(message_id, to_address, SiteSetting.soft_bounce_score) - elsif event == "dropped".freeze + elsif event == "dropped" process_bounce(message_id, to_address, SiteSetting.hard_bounce_score) end @@ -174,10 +174,10 @@ class WebhooksController < ActionController::Base to_address = data["recipient"] severity = data["severity"] - if data["event"] == "failed".freeze - if severity == "temporary".freeze + if data["event"] == "failed" + if severity == "temporary" process_bounce(message_id, to_address, SiteSetting.soft_bounce_score) - elsif severity == "permanent".freeze + elsif severity == "permanent" process_bounce(message_id, to_address, SiteSetting.hard_bounce_score) end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 00422273bb..482b2477d3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -36,7 +36,7 @@ module ApplicationHelper end def shared_session_key - if SiteSetting.long_polling_base_url != '/'.freeze && current_user + if SiteSetting.long_polling_base_url != '/' && current_user sk = "shared_session_key" return request.env[sk] if request.env[sk] @@ -282,7 +282,7 @@ module ApplicationHelper 'query-input' => 'required name=search_term_string', } } - content_tag(:script, MultiJson.dump(json).html_safe, type: 'application/ld+json'.freeze) + content_tag(:script, MultiJson.dump(json).html_safe, type: 'application/ld+json') end def gsub_emoji_to_unicode(str) diff --git a/app/jobs/regular/bulk_user_title_update.rb b/app/jobs/regular/bulk_user_title_update.rb index 97d3f68ad5..e98c024a2f 100644 --- a/app/jobs/regular/bulk_user_title_update.rb +++ b/app/jobs/regular/bulk_user_title_update.rb @@ -2,8 +2,8 @@ module Jobs class BulkUserTitleUpdate < ::Jobs::Base - UPDATE_ACTION = 'update'.freeze - RESET_ACTION = 'reset'.freeze + UPDATE_ACTION = 'update' + RESET_ACTION = 'reset' def execute(args) new_title = args[:new_title] diff --git a/app/jobs/regular/emit_web_hook_event.rb b/app/jobs/regular/emit_web_hook_event.rb index 3c7fc3414c..94371eaa33 100644 --- a/app/jobs/regular/emit_web_hook_event.rb +++ b/app/jobs/regular/emit_web_hook_event.rb @@ -4,8 +4,8 @@ require 'excon' module Jobs class EmitWebHookEvent < ::Jobs::Base - PING_EVENT = 'ping'.freeze - MAX_RETRY_COUNT = 4.freeze + PING_EVENT = 'ping' + MAX_RETRY_COUNT = 4 RETRY_BACKOFF = 5 def execute(args) diff --git a/app/jobs/scheduled/bookmark_reminder_notifications.rb b/app/jobs/scheduled/bookmark_reminder_notifications.rb index 991e0d23c1..4dca47c1f6 100644 --- a/app/jobs/scheduled/bookmark_reminder_notifications.rb +++ b/app/jobs/scheduled/bookmark_reminder_notifications.rb @@ -6,7 +6,7 @@ module Jobs # Any leftovers will be caught in the next run, because the reminder_at column # is set to NULL once a reminder has been sent. class BookmarkReminderNotifications < ::Jobs::Scheduled - JOB_RUN_NUMBER_KEY ||= 'jobs_bookmark_reminder_notifications_job_run_num'.freeze + JOB_RUN_NUMBER_KEY ||= 'jobs_bookmark_reminder_notifications_job_run_num' AT_DESKTOP_CONSISTENCY_RUN_NUMBER ||= 6 every 5.minutes diff --git a/app/jobs/scheduled/pending_queued_posts_reminder.rb b/app/jobs/scheduled/pending_queued_posts_reminder.rb index 29bc670957..c3a283bd53 100644 --- a/app/jobs/scheduled/pending_queued_posts_reminder.rb +++ b/app/jobs/scheduled/pending_queued_posts_reminder.rb @@ -41,7 +41,7 @@ module Jobs end def self.last_notified_key - "last_notified_queued_post_id".freeze + "last_notified_queued_post_id" end end end diff --git a/app/jobs/scheduled/pending_reviewables_reminder.rb b/app/jobs/scheduled/pending_reviewables_reminder.rb index df7a6a8aa3..3cc4b124a0 100644 --- a/app/jobs/scheduled/pending_reviewables_reminder.rb +++ b/app/jobs/scheduled/pending_reviewables_reminder.rb @@ -45,7 +45,7 @@ module Jobs end def self.last_notified_key - "last_notified_reviewable_id".freeze + "last_notified_reviewable_id" end def self.clear_key diff --git a/app/jobs/scheduled/pending_users_reminder.rb b/app/jobs/scheduled/pending_users_reminder.rb index 0c1be62ad8..33d212f3b2 100644 --- a/app/jobs/scheduled/pending_users_reminder.rb +++ b/app/jobs/scheduled/pending_users_reminder.rb @@ -58,7 +58,7 @@ module Jobs end def previous_newest_username_cache_key - "pending-users-reminder:newest-username".freeze + "pending-users-reminder:newest-username" end end diff --git a/app/jobs/scheduled/poll_mailbox.rb b/app/jobs/scheduled/poll_mailbox.rb index 178cbdb9bd..8592ed3fe6 100644 --- a/app/jobs/scheduled/poll_mailbox.rb +++ b/app/jobs/scheduled/poll_mailbox.rb @@ -23,7 +23,7 @@ module Jobs Email::Processor.process!(popmail.pop) end - POLL_MAILBOX_TIMEOUT_ERROR_KEY ||= "poll_mailbox_timeout_error_key".freeze + POLL_MAILBOX_TIMEOUT_ERROR_KEY ||= "poll_mailbox_timeout_error_key" def poll_pop3 pop3 = Net::POP3.new(SiteSetting.pop3_polling_host, SiteSetting.pop3_polling_port) @@ -62,7 +62,7 @@ module Jobs Discourse.handle_job_exception(e, error_context(@args, "Signing in to poll incoming emails.")) end - POLL_MAILBOX_ERRORS_KEY ||= "poll_mailbox_errors".freeze + POLL_MAILBOX_ERRORS_KEY ||= "poll_mailbox_errors" def self.errors_in_past_24_hours Discourse.redis.zremrangebyscore(POLL_MAILBOX_ERRORS_KEY, 0, 24.hours.ago.to_i) diff --git a/app/models/category_featured_topic.rb b/app/models/category_featured_topic.rb index 2848383605..cfad73d7d8 100644 --- a/app/models/category_featured_topic.rb +++ b/app/models/category_featured_topic.rb @@ -4,7 +4,7 @@ class CategoryFeaturedTopic < ActiveRecord::Base belongs_to :category belongs_to :topic - NEXT_CATEGORY_ID_KEY = 'category-featured-topic:next-category-id'.freeze + NEXT_CATEGORY_ID_KEY = 'category-featured-topic:next-category-id' DEFAULT_BATCH_SIZE = 100 # Populates the category featured topics. diff --git a/app/models/category_list.rb b/app/models/category_list.rb index 35dcaa7d3a..5c81c1afbc 100644 --- a/app/models/category_list.rb +++ b/app/models/category_list.rb @@ -40,7 +40,7 @@ class CategoryList end def preload_key - "categories_list".freeze + "categories_list" end def self.order_categories(categories) diff --git a/app/models/concerns/category_hashtag.rb b/app/models/concerns/category_hashtag.rb index 95b1521c25..c6745b0116 100644 --- a/app/models/concerns/category_hashtag.rb +++ b/app/models/concerns/category_hashtag.rb @@ -3,7 +3,7 @@ module CategoryHashtag extend ActiveSupport::Concern - SEPARATOR = ":".freeze + SEPARATOR = ":" class_methods do def query_from_hashtag_slug(category_slug) diff --git a/app/models/emoji.rb b/app/models/emoji.rb index e57fc3b81a..cfd121b76e 100644 --- a/app/models/emoji.rb +++ b/app/models/emoji.rb @@ -140,9 +140,9 @@ class Emoji def self.replacement_code(code) code - .split('-'.freeze) + .split('-') .map!(&:hex) - .pack("U*".freeze) + .pack("U*") end def self.unicode_replacements @@ -166,7 +166,7 @@ class Emoji replacements[code] = name if is_tonable_emojis.include?(name) fitzpatrick_scales.each_with_index do |scale, index| - toned_code = code.codepoints.insert(1, scale).pack("U*".freeze) + toned_code = code.codepoints.insert(1, scale).pack("U*") replacements[toned_code] = "#{name}:t#{index + 2}" end end diff --git a/app/models/topic.rb b/app/models/topic.rb index dbc6c44d15..aaeca3f145 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -228,7 +228,7 @@ class Topic < ActiveRecord::Base end after_save do - banner = "banner".freeze + banner = "banner" if archetype_before_last_save == banner || archetype == banner ApplicationController.banner_json_cache.clear diff --git a/app/models/topic_link.rb b/app/models/topic_link.rb index 2fc9fd0b84..f913dc6459 100644 --- a/app/models/topic_link.rb +++ b/app/models/topic_link.rb @@ -119,7 +119,7 @@ class TopicLink < ActiveRecord::Base uri = UrlHelper.relaxed_parse(u.url) [u, uri] end - .reject { |_, p| p.nil? || "mailto".freeze == p.scheme } + .reject { |_, p| p.nil? || "mailto" == p.scheme } .uniq { |_, p| p } .each do |link, parsed| diff --git a/app/models/topic_tracking_state.rb b/app/models/topic_tracking_state.rb index 91838da99b..df6516c382 100644 --- a/app/models/topic_tracking_state.rb +++ b/app/models/topic_tracking_state.rb @@ -10,9 +10,9 @@ class TopicTrackingState include ActiveModel::SerializerSupport CHANNEL = "/user-tracking" - UNREAD_MESSAGE_TYPE = "unread".freeze - LATEST_MESSAGE_TYPE = "latest".freeze - MUTED_MESSAGE_TYPE = "muted".freeze + UNREAD_MESSAGE_TYPE = "unread" + LATEST_MESSAGE_TYPE = "latest" + MUTED_MESSAGE_TYPE = "muted" attr_accessor :user_id, :topic_id, diff --git a/app/models/upload.rb b/app/models/upload.rb index 4cd7b926ce..cb4cf458af 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -9,7 +9,7 @@ class Upload < ActiveRecord::Base SHA1_LENGTH = 40 SEEDED_ID_THRESHOLD = 0 URL_REGEX ||= /(\/original\/\dX[\/\.\w]*\/([a-zA-Z0-9]+)[\.\w]*)/ - SECURE_MEDIA_ROUTE = "secure-media-uploads".freeze + SECURE_MEDIA_ROUTE = "secure-media-uploads" belongs_to :user belongs_to :access_control_post, class_name: 'Post' diff --git a/app/models/user.rb b/app/models/user.rb index 562291438f..0beec5739a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -352,7 +352,7 @@ class User < ActiveRecord::Base end EMAIL = %r{([^@]+)@([^\.]+)} - FROM_STAGED = "from_staged".freeze + FROM_STAGED = "from_staged" def self.new_from_params(params) user = User.new @@ -598,7 +598,7 @@ class User < ActiveRecord::Base notification = notifications.visible.order('notifications.created_at desc').first json = NotificationSerializer.new(notification).as_json if notification - sql = (<<~SQL).freeze + sql = (<<~SQL) SELECT * FROM ( SELECT n.id, n.read FROM notifications n LEFT JOIN topics t ON n.topic_id = t.id diff --git a/app/serializers/incoming_email_details_serializer.rb b/app/serializers/incoming_email_details_serializer.rb index 420951bb8b..d248a3ac58 100644 --- a/app/serializers/incoming_email_details_serializer.rb +++ b/app/serializers/incoming_email_details_serializer.rb @@ -15,7 +15,7 @@ class IncomingEmailDetailsSerializer < ApplicationSerializer @mail = Mail.new(incoming_email.raw) end - EMAIL_RECEIVER_ERROR_PREFIX = "Email::Receiver::".freeze + EMAIL_RECEIVER_ERROR_PREFIX = "Email::Receiver::" def error @error_string.presence || I18n.t("emails.incoming.unrecognized_error") diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 26b9262a3a..afa1a3cc3d 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -180,7 +180,7 @@ class BadgeGranter end def self.queue_key - "badge_queue".freeze + "badge_queue" end # Options: diff --git a/config/initializers/100-silence_logger.rb b/config/initializers/100-silence_logger.rb index 38fdbef5aa..3a900d24e3 100644 --- a/config/initializers/100-silence_logger.rb +++ b/config/initializers/100-silence_logger.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class SilenceLogger < Rails::Rack::Logger - PATH_INFO = 'PATH_INFO'.freeze - HTTP_X_SILENCE_LOGGER = 'HTTP_X_SILENCE_LOGGER'.freeze + PATH_INFO = 'PATH_INFO' + HTTP_X_SILENCE_LOGGER = 'HTTP_X_SILENCE_LOGGER' def initialize(app, opts = {}) @app = app @@ -36,9 +36,9 @@ class SilenceLogger < Rails::Rack::Logger end silenced = [ - "/mini-profiler-resources/results".freeze, - "/mini-profiler-resources/includes.js".freeze, - "/mini-profiler-resources/includes.css".freeze, - "/mini-profiler-resources/jquery.tmpl.js".freeze + "/mini-profiler-resources/results", + "/mini-profiler-resources/includes.js", + "/mini-profiler-resources/includes.css", + "/mini-profiler-resources/jquery.tmpl.js" ] Rails.configuration.middleware.swap Rails::Rack::Logger, SilenceLogger, silenced: silenced diff --git a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb index ce37de7c14..b8bfb62909 100644 --- a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb +++ b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb @@ -11,7 +11,7 @@ class PostgreSQLFallbackHandler attr_reader :masters_down attr_accessor :initialized - DATABASE_DOWN_CHANNEL = '/global/database_down'.freeze + DATABASE_DOWN_CHANNEL = '/global/database_down' def initialize @masters_down = DistributedCache.new('masters_down', namespace: false) diff --git a/lib/badge_posts_view_manager.rb b/lib/badge_posts_view_manager.rb index 52ef2084c3..13b5d09607 100644 --- a/lib/badge_posts_view_manager.rb +++ b/lib/badge_posts_view_manager.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class BadgePostsViewManager - VIEW_NAME = "badge_posts".freeze + VIEW_NAME = "badge_posts" def self.create! sql = <<~SQL diff --git a/lib/base62.rb b/lib/base62.rb index f745922e63..70728c6a52 100644 --- a/lib/base62.rb +++ b/lib/base62.rb @@ -3,7 +3,7 @@ # Modified version of: https://github.com/steventen/base62-rb module Base62 - KEYS ||= "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".freeze + KEYS ||= "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" KEYS_HASH ||= KEYS.each_char.with_index.to_h BASE ||= KEYS.length diff --git a/lib/bookmark_reminder_notification_handler.rb b/lib/bookmark_reminder_notification_handler.rb index 3354be3949..e129b4ac19 100644 --- a/lib/bookmark_reminder_notification_handler.rb +++ b/lib/bookmark_reminder_notification_handler.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class BookmarkReminderNotificationHandler - PENDING_AT_DESKTOP_KEY_PREFIX ||= 'pending_at_desktop_bookmark_reminder_user_'.freeze + PENDING_AT_DESKTOP_KEY_PREFIX ||= 'pending_at_desktop_bookmark_reminder_user_' PENDING_AT_DESKTOP_EXPIRY_DAYS ||= 20 def self.send_notification(bookmark) diff --git a/lib/discourse.rb b/lib/discourse.rb index 07810010b6..9bdbc2b302 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -42,7 +42,7 @@ module Discourse end def self.pretty_logs(logs) - logs.join("\n".freeze) + logs.join("\n") end def self.atomic_write_file(destination, contents) @@ -811,7 +811,7 @@ module Discourse warning end - SIDEKIQ_NAMESPACE ||= 'sidekiq'.freeze + SIDEKIQ_NAMESPACE ||= 'sidekiq' def self.sidekiq_redis_config conf = GlobalSetting.redis_config.dup diff --git a/lib/discourse_redis.rb b/lib/discourse_redis.rb index 728e244db7..ff946cacfb 100644 --- a/lib/discourse_redis.rb +++ b/lib/discourse_redis.rb @@ -8,10 +8,10 @@ class DiscourseRedis class FallbackHandler include Singleton - MASTER_ROLE_STATUS = "role:master".freeze - MASTER_LOADING_STATUS = "loading:1".freeze - MASTER_LOADED_STATUS = "loading:0".freeze - CONNECTION_TYPES = %w{normal pubsub}.each(&:freeze) + MASTER_ROLE_STATUS = "role:master" + MASTER_LOADING_STATUS = "loading:1" + MASTER_LOADED_STATUS = "loading:0" + CONNECTION_TYPES = %w{normal pubsub} def initialize @master = true diff --git a/lib/email/message_builder.rb b/lib/email/message_builder.rb index 4dafa6bbf9..611cdca115 100644 --- a/lib/email/message_builder.rb +++ b/lib/email/message_builder.rb @@ -6,7 +6,7 @@ module Email class MessageBuilder attr_reader :template_args - ALLOW_REPLY_BY_EMAIL_HEADER = 'X-Discourse-Allow-Reply-By-Email'.freeze + ALLOW_REPLY_BY_EMAIL_HEADER = 'X-Discourse-Allow-Reply-By-Email' def initialize(to, opts = nil) @to = to diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 4d299fcff3..34845f9df6 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -337,8 +337,8 @@ module Email def strip_classes_and_ids @fragment.css('*').each do |element| - element.delete('class'.freeze) - element.delete('id'.freeze) + element.delete('class') + element.delete('id') end end diff --git a/lib/file_store/base_store.rb b/lib/file_store/base_store.rb index c3752be155..6307465a8f 100644 --- a/lib/file_store/base_store.rb +++ b/lib/file_store/base_store.rb @@ -121,14 +121,14 @@ module FileStore File.extname(upload.original_filename) end - get_path_for("original".freeze, upload.id, upload.sha1, extension) + get_path_for("original", upload.id, upload.sha1, extension) end def get_path_for_optimized_image(optimized_image) upload = optimized_image.upload version = optimized_image.version || 1 extension = "_#{version}_#{optimized_image.width}x#{optimized_image.height}#{optimized_image.extension}" - get_path_for("optimized".freeze, upload.id, upload.sha1, extension) + get_path_for("optimized", upload.id, upload.sha1, extension) end CACHE_DIR ||= "#{Rails.root}/tmp/download_cache/" diff --git a/lib/html_prettify.rb b/lib/html_prettify.rb index db3bd14e08..06a00099b2 100644 --- a/lib/html_prettify.rb +++ b/lib/html_prettify.rb @@ -240,11 +240,11 @@ class HtmlPrettify < String def educate_fractions(str) str.gsub(/(\s+|^)(1\/4|1\/2|3\/4)([,.;\s]|$)/) do frac = - if $2 == "1/2".freeze + if $2 == "1/2" entity(:frac12) - elsif $2 == "1/4".freeze + elsif $2 == "1/4" entity(:frac14) - elsif $2 == "3/4".freeze + elsif $2 == "3/4" entity(:frac34) end "#{$1}#{frac}#{$3}" diff --git a/lib/migration/base_dropper.rb b/lib/migration/base_dropper.rb index 2ea01131e2..b88a5ba357 100644 --- a/lib/migration/base_dropper.rb +++ b/lib/migration/base_dropper.rb @@ -2,7 +2,7 @@ module Migration class BaseDropper - FUNCTION_SCHEMA_NAME ||= "discourse_functions".freeze + FUNCTION_SCHEMA_NAME ||= "discourse_functions" def self.create_readonly_function(table_name, column_name = nil) DB.exec <<~SQL diff --git a/lib/plain_text_to_markdown.rb b/lib/plain_text_to_markdown.rb index f365731130..5cbe78a934 100644 --- a/lib/plain_text_to_markdown.rb +++ b/lib/plain_text_to_markdown.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class PlainTextToMarkdown - SIGNATURE_SEPARATOR ||= "-- ".freeze + SIGNATURE_SEPARATOR ||= "-- " def initialize(plaintext, opts = {}) @plaintext = plaintext diff --git a/lib/post_creator.rb b/lib/post_creator.rb index fab3de1954..6f91e35b5d 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -240,7 +240,7 @@ class PostCreator end def self.track_post_stats - Rails.env != "test".freeze || @track_post_stats + Rails.env != "test" || @track_post_stats end def self.track_post_stats=(val) diff --git a/lib/pretty_text.rb b/lib/pretty_text.rb index 0843f32348..8f260089ef 100644 --- a/lib/pretty_text.rb +++ b/lib/pretty_text.rb @@ -311,7 +311,7 @@ module PrettyText # extract all links doc.css("a").each do |a| - if a["href"].present? && a["href"][0] != "#".freeze + if a["href"].present? && a["href"][0] != "#" links << DetectedLink.new(a["href"], false) end end diff --git a/lib/quote_comparer.rb b/lib/quote_comparer.rb index e3aeb79717..5da2891a7e 100644 --- a/lib/quote_comparer.rb +++ b/lib/quote_comparer.rb @@ -2,7 +2,7 @@ class QuoteComparer def self.whitespace - " \t\r\n".freeze + " \t\r\n" end def initialize(topic_id, post_number, text) diff --git a/lib/s3_helper.rb b/lib/s3_helper.rb index a1f921e9af..ccc0da333a 100644 --- a/lib/s3_helper.rb +++ b/lib/s3_helper.rb @@ -28,7 +28,7 @@ class S3Helper end def self.get_bucket_and_folder_path(s3_bucket_name) - s3_bucket_name.downcase.split("/".freeze, 2) + s3_bucket_name.downcase.split("/", 2) end def upload(file, path, options = {}) @@ -75,7 +75,7 @@ class S3Helper options[:copy_source] = File.join(@s3_bucket_name, source) elsif @s3_bucket_folder_path folder, filename = begin - source.split("/".freeze, 2) + source.split("/", 2) end options[:copy_source] = File.join(@s3_bucket_name, folder, multisite_upload_path, filename) else diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index 2c651d0b61..64fe9d6d44 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -135,7 +135,7 @@ module SiteSettingExtension if GlobalSetting.respond_to?(name) val = GlobalSetting.public_send(name) - unless val.nil? || (val == ''.freeze) + unless val.nil? || (val == '') shadowed_val = val hidden_settings << name shadowed_settings << name diff --git a/lib/topic_query.rb b/lib/topic_query.rb index fa851e916a..35bc7347fe 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -458,7 +458,7 @@ class TopicQuery def latest_results(options = {}) result = default_results(options) - result = remove_muted_topics(result, @user) unless options && options[:state] == "muted".freeze + result = remove_muted_topics(result, @user) unless options && options[:state] == "muted" result = remove_muted_categories(result, @user, exclude: options[:category]) result = remove_muted_tags(result, @user, options) result = apply_shared_drafts(result, get_category_id(options[:category]), options) diff --git a/lib/twitter_api.rb b/lib/twitter_api.rb index 8b9f088767..2cef9c0847 100644 --- a/lib/twitter_api.rb +++ b/lib/twitter_api.rb @@ -93,7 +93,7 @@ class TwitterApi end unless defined? BASE_URL - BASE_URL = 'https://api.twitter.com'.freeze + BASE_URL = 'https://api.twitter.com' end def twitter_get(uri) diff --git a/lib/validators/censored_words_validator.rb b/lib/validators/censored_words_validator.rb index b65f6620e3..0c72e51a31 100644 --- a/lib/validators/censored_words_validator.rb +++ b/lib/validators/censored_words_validator.rb @@ -29,7 +29,7 @@ class CensoredWordsValidator < ActiveModel::EachValidator def join_censored_words(censored_words) censored_words.map!(&:downcase) censored_words.uniq! - censored_words.join(", ".freeze) + censored_words.join(", ") end def censored_words_regexp diff --git a/lib/validators/regex_setting_validator.rb b/lib/validators/regex_setting_validator.rb index aec1dbc1a6..a0d85b9e5e 100644 --- a/lib/validators/regex_setting_validator.rb +++ b/lib/validators/regex_setting_validator.rb @@ -2,7 +2,7 @@ class RegexSettingValidator - LOREM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam eget sem non elit tincidunt rhoncus.'.freeze + LOREM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam eget sem non elit tincidunt rhoncus.' def initialize(opts = {}) @opts = opts diff --git a/lib/webauthn.rb b/lib/webauthn.rb index 56705cfa23..4734b660ca 100644 --- a/lib/webauthn.rb +++ b/lib/webauthn.rb @@ -5,8 +5,8 @@ require 'webauthn/security_key_registration_service' require 'webauthn/security_key_authentication_service' module Webauthn - ACCEPTABLE_REGISTRATION_TYPE = "webauthn.create".freeze - ACCEPTABLE_AUTHENTICATION_TYPE = "webauthn.get".freeze + ACCEPTABLE_REGISTRATION_TYPE = "webauthn.create" + ACCEPTABLE_AUTHENTICATION_TYPE = "webauthn.get" # -7 - ES256 # -257 - RS256 (Windows Hello supported alg.) diff --git a/script/bulk_import/base.rb b/script/bulk_import/base.rb index 8af89155e1..9fc7b1cd17 100644 --- a/script/bulk_import/base.rb +++ b/script/bulk_import/base.rb @@ -26,7 +26,7 @@ module BulkImport; end class BulkImport::Base - NOW ||= "now()".freeze + NOW ||= "now()" PRIVATE_OFFSET ||= 2**30 # rubocop:disable Layout/HashAlignment @@ -660,7 +660,7 @@ class BulkImport::Base imported_ids << mapped[:imported_id] unless mapped[:imported_id].nil? imported_ids |= mapped[:imported_ids] unless mapped[:imported_ids].nil? @raw_connection.put_copy_data columns.map { |c| processed[c] } - print "\r%7d - %6d/sec".freeze % [imported_ids.size, imported_ids.size.to_f / (Time.now - start)] if imported_ids.size % 5000 == 0 + print "\r%7d - %6d/sec" % [imported_ids.size, imported_ids.size.to_f / (Time.now - start)] if imported_ids.size % 5000 == 0 rescue => e puts "\n" puts "ERROR: #{e.inspect}" @@ -669,7 +669,7 @@ class BulkImport::Base end if imported_ids.size > 0 - print "\r%7d - %6d/sec".freeze % [imported_ids.size, imported_ids.size.to_f / (Time.now - start)] + print "\r%7d - %6d/sec" % [imported_ids.size, imported_ids.size.to_f / (Time.now - start)] puts end diff --git a/script/bulk_import/discourse_merger.rb b/script/bulk_import/discourse_merger.rb index 9029bdb28a..35ff800822 100644 --- a/script/bulk_import/discourse_merger.rb +++ b/script/bulk_import/discourse_merger.rb @@ -4,7 +4,7 @@ require_relative "base" class BulkImport::DiscourseMerger < BulkImport::Base - NOW ||= "now()".freeze + NOW ||= "now()" CUSTOM_FIELDS = ['category', 'group', 'post', 'topic', 'user'] # DB_NAME: name of database being merged into the current local db diff --git a/script/bulk_import/vanilla.rb b/script/bulk_import/vanilla.rb index 2efed5f31f..71307dba0a 100644 --- a/script/bulk_import/vanilla.rb +++ b/script/bulk_import/vanilla.rb @@ -209,7 +209,7 @@ class BulkImport::Vanilla < BulkImport::Base User.find_each do |u| count += 1 - print "\r%7d - %6d/sec".freeze % [count, count.to_f / (Time.now - start)] + print "\r%7d - %6d/sec" % [count, count.to_f / (Time.now - start)] next unless u.custom_fields["import_id"] @@ -276,7 +276,7 @@ class BulkImport::Vanilla < BulkImport::Base Post.where("raw LIKE '%/us.v-cdn.net/%' OR raw LIKE '%[attachment%'").find_each do |post| count += 1 - print "\r%7d - %6d/sec".freeze % [count, count.to_f / (Time.now - start)] + print "\r%7d - %6d/sec" % [count, count.to_f / (Time.now - start)] new_raw = post.raw.dup new_raw.gsub!(attachment_regex) do |s| @@ -613,7 +613,7 @@ class BulkImport::Vanilla < BulkImport::Base ) end - print "\r%7d - %6d/sec".freeze % [count, count.to_f / (Time.now - start)] if count % 5000 == 0 + print "\r%7d - %6d/sec" % [count, count.to_f / (Time.now - start)] if count % 5000 == 0 end end @@ -645,7 +645,7 @@ class BulkImport::Vanilla < BulkImport::Base end end - print "\r%7d - %6d/sec".freeze % [count, count.to_f / (Time.now - start)] if count % 5000 == 0 + print "\r%7d - %6d/sec" % [count, count.to_f / (Time.now - start)] if count % 5000 == 0 end end end diff --git a/script/bulk_import/vbulletin.rb b/script/bulk_import/vbulletin.rb index fef661fa91..b437137c38 100644 --- a/script/bulk_import/vbulletin.rb +++ b/script/bulk_import/vbulletin.rb @@ -608,7 +608,7 @@ class BulkImport::VBulletin < BulkImport::Base count = 0 Dir.foreach(AVATAR_DIR) do |item| - print "\r%7d - %6d/sec".freeze % [count, count.to_f / (Time.now - start)] + print "\r%7d - %6d/sec" % [count, count.to_f / (Time.now - start)] next if item == ('.') || item == ('..') || item == ('.DS_Store') next unless item =~ /avatar(\d+)_(\d).gif/ diff --git a/script/import_scripts/mbox/support/indexer.rb b/script/import_scripts/mbox/support/indexer.rb index 7017c2a59f..dc6e092c29 100644 --- a/script/import_scripts/mbox/support/indexer.rb +++ b/script/import_scripts/mbox/support/indexer.rb @@ -39,7 +39,7 @@ module ImportScripts::Mbox private - METADATA_FILENAME = 'metadata.yml'.freeze + METADATA_FILENAME = 'metadata.yml' IGNORED_FILE_EXTENSIONS = ['.dbindex', '.dbnames', '.digest', '.subjects', '.yml'] def index_category(directory) diff --git a/spec/components/discourse_tagging_spec.rb b/spec/components/discourse_tagging_spec.rb index 35ff67a9a9..b8d328f980 100644 --- a/spec/components/discourse_tagging_spec.rb +++ b/spec/components/discourse_tagging_spec.rb @@ -475,7 +475,7 @@ describe DiscourseTagging do describe "clean_tag" do it "downcases new tags if setting enabled" do - expect(DiscourseTagging.clean_tag("HeLlO".freeze)).to eq("hello") + expect(DiscourseTagging.clean_tag("HeLlO")).to eq("hello") SiteSetting.force_lowercase_tags = false expect(DiscourseTagging.clean_tag("HeLlO")).to eq("HeLlO") diff --git a/spec/support/webauthn_integration_helpers.rb b/spec/support/webauthn_integration_helpers.rb index d6a32ffd35..09310d0f57 100644 --- a/spec/support/webauthn_integration_helpers.rb +++ b/spec/support/webauthn_integration_helpers.rb @@ -19,23 +19,23 @@ module WebauthnIntegrationHelpers # simulate_localhost_webautn_challenge for a real example. def valid_security_key_data { - credential_id: "9GiFosW50+s+juyJlyxKEVAsk3gZLo9XWIhX47eC4gHfDsldF3TWR43Tcl/+3gLTL5t1TjpmcbKA2DUV2eKrBw==".freeze, - public_key: "pQECAyYgASFYIPMGM1OpSuCU5uks+BulAdfVxdlJiYcgGac5Y+LnLXC9Ilgghy0BKvRvptmQdtWz33Jjnf8Y6+HD85XdRiqmo1KMGPE=".freeze + credential_id: "9GiFosW50+s+juyJlyxKEVAsk3gZLo9XWIhX47eC4gHfDsldF3TWR43Tcl/+3gLTL5t1TjpmcbKA2DUV2eKrBw==", + public_key: "pQECAyYgASFYIPMGM1OpSuCU5uks+BulAdfVxdlJiYcgGac5Y+LnLXC9Ilgghy0BKvRvptmQdtWz33Jjnf8Y6+HD85XdRiqmo1KMGPE=" } end def valid_security_key_auth_post_data { - signature: "MEYCIQC5xyUQvF4qTPZ2yX7crp/IEs1E/4wqhXgxC1EVAumhfgIhAIC/7w4BVEy+ew6vMYISahtnnIqbqsPZosBeTUSI8Y4j".freeze, - clientData: "eyJjaGFsbGVuZ2UiOiJOR1UzWW1Zek0yWTBNelkyWkdFM05EVTNZak5qWldVNFpUWTNOakJoTm1NMFlqVTVORFptTlRrd016Vm1ZMlZpTURVd01UZzJOemcxTW1RMSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsInR5cGUiOiJ3ZWJhdXRobi5nZXQifQ==".freeze, - authenticatorData: "SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MBAAAA2Q==".freeze, + signature: "MEYCIQC5xyUQvF4qTPZ2yX7crp/IEs1E/4wqhXgxC1EVAumhfgIhAIC/7w4BVEy+ew6vMYISahtnnIqbqsPZosBeTUSI8Y4j", + clientData: "eyJjaGFsbGVuZ2UiOiJOR1UzWW1Zek0yWTBNelkyWkdFM05EVTNZak5qWldVNFpUWTNOakJoTm1NMFlqVTVORFptTlRrd016Vm1ZMlZpTURVd01UZzJOemcxTW1RMSIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCIsInR5cGUiOiJ3ZWJhdXRobi5nZXQifQ==", + authenticatorData: "SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2MBAAAA2Q==", credentialId: valid_security_key_data[:credential_id] } end def valid_security_key_challenge_data { - challenge: "4e7bf33f4366da7457b3cee8e6760a6c4b5946f59035fceb0501867852d5".freeze + challenge: "4e7bf33f4366da7457b3cee8e6760a6c4b5946f59035fceb0501867852d5" } end From 238cbff46f4b24acf07211583a1bc854ceefab9a Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Thu, 30 Apr 2020 11:02:15 +0300 Subject: [PATCH 0882/1830] Revert "HACK: Add dummy plugin folder" This reverts commit 590830b931ec83f7ae4ccde3cf820a072d6c2d09 because a proper fix was implemented in discourse_docker@d587158. --- .gitignore | 1 - plugins/discourse-internet-explorer/public/.gitkeep | 0 2 files changed, 1 deletion(-) delete mode 100644 plugins/discourse-internet-explorer/public/.gitkeep diff --git a/.gitignore b/.gitignore index 46e956c118..97d1a6b930 100644 --- a/.gitignore +++ b/.gitignore @@ -54,7 +54,6 @@ bootsnap-compile-cache/ !/plugins/discourse-narrative-bot !/plugins/discourse-presence !/plugins/discourse-local-dates -!/plugins/discourse-internet-explorer !/plugins/discourse-unsupported-browser /plugins/*/auto_generated/ diff --git a/plugins/discourse-internet-explorer/public/.gitkeep b/plugins/discourse-internet-explorer/public/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 From fe51f7a863b68abfe592d564b0e96c3f65e66415 Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Thu, 30 Apr 2020 12:07:51 +0300 Subject: [PATCH 0883/1830] FEATURE: More improvements to crawler and old browsers view Related to c85018cdfd1a36e8c33de25c44bf192d53e201c1. --- app/assets/javascripts/polyfills.js | 2 +- app/assets/stylesheets/common/base/_topic-list.scss | 6 ------ app/assets/stylesheets/common/base/crawler_layout.scss | 8 ++++---- app/views/list/list.erb | 8 +++++--- app/views/topics/show.html.erb | 2 +- config/locales/client.en.yml | 2 +- 6 files changed, 12 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/polyfills.js b/app/assets/javascripts/polyfills.js index 358a213467..0fe25c8bdb 100644 --- a/app/assets/javascripts/polyfills.js +++ b/app/assets/javascripts/polyfills.js @@ -1,6 +1,6 @@ /* eslint-disable */ -// Any IE only polyfill should be moved in discourse-internet-explorer plugin +// Any IE only polyfill should be moved in discourse-unsupported-browser plugin // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/flags#Polyfill // IE and EDGE diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index 01fc70a2bb..5b9cff0076 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -142,12 +142,6 @@ } } - .link-bottom-line { - .category-name { - margin-right: 12px; - } - } - .unread-indicator { &.read { display: none; diff --git a/app/assets/stylesheets/common/base/crawler_layout.scss b/app/assets/stylesheets/common/base/crawler_layout.scss index c0ca931510..b0588f35b5 100644 --- a/app/assets/stylesheets/common/base/crawler_layout.scss +++ b/app/assets/stylesheets/common/base/crawler_layout.scss @@ -11,6 +11,10 @@ body.crawler { box-sizing: border-box; } + .header-buttons { + display: none; + } + div#main-outlet { div.post { word-break: break-word; @@ -29,10 +33,6 @@ body.crawler { margin-top: 4em; } - .category-title { - color: $primary; - } - .discourse-tags { color: $primary-medium; } diff --git a/app/views/list/list.erb b/app/views/list/list.erb index 77bb68d2e4..9fa5a1f034 100644 --- a/app/views/list/list.erb +++ b/app/views/list/list.erb @@ -69,7 +69,9 @@ <% if (!@category || @category.has_children?) && t.category %> - <%= t.category.name %> + + <%= t.category.name %> + <% end %> <% if t.tags %> @@ -99,10 +101,10 @@ <% end %> - '><%= t.views %> + '><%= t.posts_count %> - '><%= t.posts_count %> + '><%= t.views %> <%= I18n.l(t.last_posted_at || t.created_at, format: :date_only) %> diff --git a/app/views/topics/show.html.erb b/app/views/topics/show.html.erb index e9d3b96b9a..801e0a0973 100644 --- a/app/views/topics/show.html.erb +++ b/app/views/topics/show.html.erb @@ -11,7 +11,7 @@ - <%= c[:name] %> + <%= c[:name] %> diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index da09ba9c9e..61a29cb70e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3052,7 +3052,7 @@ en: today: "Today" other_periods: "see top" - browser_update: 'Unfortunately, your browser is too old to work on this site. Please upgrade your browser.' + browser_update: 'Unfortunately, your browser is too old to work on this site. Please upgrade your browser to view rich content, login, and reply.' permission_types: full: "Create / Reply / See" From 501b19b6e005f00ffbaa126965b80bad3eaca47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 30 Apr 2020 12:21:25 +0200 Subject: [PATCH 0884/1830] FIX: server-side HtmlToMarkdown improvements (#9586) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TLDR; this commit vastly improves how whitespaces are handled when converting from HTML to Markdown. It also adds support for converting HTML to markdown tables. The previous 'remove_whitespaces!' method was traversing the whole HTML tree and used a heuristic to remove leading and trailing whitespaces whenever it was appropriate (ie. mostly before and after HTML block elements) It was a good idea, but it was very limited and leaded to bad conversion when the html had leading whitespaces on several lines for example. One such example can be found [here](https://meta.discourse.org/t/86782). For various reasons, most of the whitespaces in a HTML file is ignored when the page is being displayed in a browser. The rules that the browsers follow are the [CSS' White Space Processing Rules](https://www.w3.org/TR/css-text-3/#white-space-rules). They can be quite complicated when you take into account RTL languages and other various tidbits but they boils down to the following: - Collapse whitespaces down to one space (0x20) inside an inline context (ie. nodes/tags that are being displaying on the same line) - Remove any leading/trailing whitespaces inside an inline context One quick & dirty way of getting this 90% solved would be to do 'HTML.gsub!(/[[:space:]]+/, " ")'. We would also need to hoist
     elements in order to not mess with their whitespaces.
    Unfortunately, this solution let some whitespaces creep around HTML tags which leads to more '.strip!' calls than I can bear.
    
    I decided to "emulate" the browser's handling of whitespaces and came up with a solution in 4 parts
    
    1. remove_not_allowed!
    
    The HtmlToMarkdown library is recursively "visiting" all the nodes in the HTML in order to convert them to Markdown.
    All the nodes that aren't handled by the library (eg. [/img]"
    -    html = '

    ' + html = '

    ' expect(cooked).to eq(html) end @@ -1433,10 +1433,10 @@ HTML html = <<~HTML

    title with | title
    -
    -
    +
    +
    stuff
    -

    +

    HTML expect(cooked).to eq(html.strip) @@ -1452,11 +1452,11 @@ HTML MD html = <<~HTML -


    -
    -
    -
    -

    +


    +
    +
    +
    +

    HTML expect(cooked).to eq(html.strip) diff --git a/spec/lib/content_security_policy_spec.rb b/spec/lib/content_security_policy_spec.rb index 168887cd47..4196b29d66 100644 --- a/spec/lib/content_security_policy_spec.rb +++ b/spec/lib/content_security_policy_spec.rb @@ -217,9 +217,9 @@ describe ContentSecurityPolicy do policy # call this first to make sure further actions clear the cache theme.set_field(target: :common, name: "header", value: <<~SCRIPT) - + + SCRIPT diff --git a/spec/models/topic_embed_spec.rb b/spec/models/topic_embed_spec.rb index c45a2209e1..ddfbe115ec 100644 --- a/spec/models/topic_embed_spec.rb +++ b/spec/models/topic_embed_spec.rb @@ -14,7 +14,7 @@ describe TopicEmbed do fab!(:user) { Fabricate(:user) } let(:title) { "How to turn a fish from good to evil in 30 seconds" } let(:url) { 'http://eviltrout.com/123' } - let(:contents) { "hello world new post hello " } + let(:contents) { "

    hello world new post hello

    " } fab!(:embeddable_host) { Fabricate(:embeddable_host) } it "returns nil when the URL is malformed" do @@ -46,7 +46,7 @@ describe TopicEmbed do it "Supports updating the post content" do expect do - TopicEmbed.import(user, url, "New title received", "muhahaha new contents!") + TopicEmbed.import(user, url, "New title received", "

    muhahaha new contents!

    ") end.to change { topic_embed.reload.content_sha1 } expect(topic_embed.topic.title).to eq("New title received") diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb index 97293742d3..e4b0cec35c 100644 --- a/spec/requests/categories_controller_spec.rb +++ b/spec/requests/categories_controller_spec.rb @@ -11,7 +11,7 @@ describe CategoriesController do it 'web crawler view has correct urls for subfolder install' do set_subfolder "/forum" get '/categories', headers: { 'HTTP_USER_AGENT' => 'Googlebot' } - html = Nokogiri::HTML(response.body) + html = Nokogiri::HTML5(response.body) expect(html.css('body.crawler')).to be_present expect(html.css("a[href=\"/forum/c/#{category.slug}\"]")).to be_present end diff --git a/spec/requests/email_controller_spec.rb b/spec/requests/email_controller_spec.rb index 10658907b6..ec60265f66 100644 --- a/spec/requests/email_controller_spec.rb +++ b/spec/requests/email_controller_spec.rb @@ -231,7 +231,7 @@ RSpec.describe EmailController do navigate_to_unsubscribe - source = Nokogiri::HTML::fragment(response.body) + source = Nokogiri::HTML5::fragment(response.body) expect(source.css(".combobox option").map(&:inner_text)).to eq(slow_digest_frequencies) end @@ -242,7 +242,7 @@ RSpec.describe EmailController do navigate_to_unsubscribe - source = Nokogiri::HTML::fragment(response.body) + source = Nokogiri::HTML5::fragment(response.body) expect(source.css(".combobox option[selected='selected']")[0]['value']).to eq(six_months_freq.to_s) end @@ -253,7 +253,7 @@ RSpec.describe EmailController do navigate_to_unsubscribe - source = Nokogiri::HTML::fragment(response.body) + source = Nokogiri::HTML5::fragment(response.body) expect(source.css(".combobox option[selected='selected']")[0]['value']).to eq(never_frequency.to_s) end end diff --git a/spec/requests/embed_controller_spec.rb b/spec/requests/embed_controller_spec.rb index 71d6eef807..ac0d6c3aa8 100644 --- a/spec/requests/embed_controller_spec.rb +++ b/spec/requests/embed_controller_spec.rb @@ -146,7 +146,7 @@ describe EmbedController do get '/embed/comments', params: { embed_url: embed_url }, headers: headers - html = Nokogiri::HTML.fragment(response.body) + html = Nokogiri::HTML5.fragment(response.body) css_link = html.at("link[data-target=embedded_theme]").attribute("href").value get css_link diff --git a/spec/requests/user_api_keys_controller_spec.rb b/spec/requests/user_api_keys_controller_spec.rb index 8148bef88a..c612eb55a1 100644 --- a/spec/requests/user_api_keys_controller_spec.rb +++ b/spec/requests/user_api_keys_controller_spec.rb @@ -238,7 +238,7 @@ describe UserApiKeysController do SiteSetting.min_trust_level_for_user_api_key = 0 post "/user-api-key", params: args expect(response.status).not_to eq(302) - payload = Nokogiri::HTML(response.body).at('code').content + payload = Nokogiri::HTML5(response.body).at('code').content encrypted = Base64.decode64(payload) key = OpenSSL::PKey::RSA.new(private_key) parsed = JSON.parse(key.private_decrypt(encrypted)) diff --git a/spec/services/username_changer_spec.rb b/spec/services/username_changer_spec.rb index 0013c82a94..416c986ca9 100644 --- a/spec/services/username_changer_spec.rb +++ b/spec/services/username_changer_spec.rb @@ -142,7 +142,7 @@ describe UsernameChanger do post = create_post_and_change_username(raw: ".@foo -@foo %@foo _@foo ,@foo ;@foo @@foo") expect(post.raw).to eq(".@bar -@bar %@bar _@bar ,@bar ;@bar @@bar") - expect(post.cooked).to match_html(<<~HTML) + expect(post.cooked).to match_html(<<~HTML.rstrip)

    .@bar -@bar %@bar @@ -164,7 +164,7 @@ describe UsernameChanger do post = create_post_and_change_username(raw: "**@foo** *@foo* _@foo_ ~~@foo~~") expect(post.raw).to eq("**@bar** *@bar* _@bar_ ~~@bar~~") - expect(post.cooked).to match_html(<<~HTML) + expect(post.cooked).to match_html(<<~HTML.rstrip)

    @bar @bar @bar @@ -176,7 +176,7 @@ describe UsernameChanger do post = create_post_and_change_username(raw: "@foo. @foo, @foo: @foo; @foo_ @foo-") expect(post.raw).to eq("@bar. @bar, @bar: @bar; @bar_ @bar-") - expect(post.cooked).to match_html(<<~HTML) + expect(post.cooked).to match_html(<<~HTML.rstrip)

    @bar. @bar, @bar: @@ -220,12 +220,8 @@ describe UsernameChanger do post = create_post_and_change_username(raw: "@foo @foobar @foo-bar @foo_bar @foo1") expect(post.raw).to eq("@bar @foobar @foo-bar @foo_bar @foo1") - expect(post.cooked).to match_html(<<~HTML) -

    @bar - @foobar - @foo-bar - @foo_bar - @foo1

    + expect(post.cooked).to match_html(<<~HTML.rstrip) +

    @bar @foobar @foo-bar @foo_bar @foo1

    HTML end @@ -311,12 +307,8 @@ describe UsernameChanger do post = create_post_and_change_username(raw: "@թռչուն @թռչուն鳥 @թռչուն-鳥 @թռչուն_鳥 @թռչուն٩", target_username: 'птица') expect(post.raw).to eq("@птица @թռչուն鳥 @թռչուն-鳥 @թռչուն_鳥 @թռչուն٩") - expect(post.cooked).to match_html(<<~HTML) -

    @птица - @թռչուն鳥 - @թռչուն-鳥 - @թռչուն_鳥 - @թռչուն٩

    + expect(post.cooked).to match_html(<<~HTML.rstrip) +

    @птица @թռչուն鳥 @թռչուն-鳥 @թռչուն_鳥 @թռչուն٩

    HTML end @@ -364,7 +356,7 @@ describe UsernameChanger do dolor sit amet RAW - expect(post.cooked).to match_html(<<~HTML) + expect(post.cooked).to match_html(<<~HTML.rstrip)

    Lorem ipsum

    quoted post

    @@ -415,7 +407,7 @@ describe UsernameChanger do end let(:expected_cooked) do - <<~HTML + <<~HTML.rstrip

    Lorem ipsum