about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile2
-rw-r--r--Gemfile8
-rw-r--r--Gemfile.lock56
-rw-r--r--app/chewy/statuses_index.rb5
-rw-r--r--app/controllers/admin/email_domain_blocks_controller.rb28
-rw-r--r--app/controllers/admin/warning_presets_controller.rb6
-rw-r--r--app/controllers/api/v1/accounts/follower_accounts_controller.rb2
-rw-r--r--app/controllers/api/v1/accounts/following_accounts_controller.rb2
-rw-r--r--app/controllers/api/v1/media_controller.rb29
-rw-r--r--app/controllers/api/v2/media_controller.rb12
-rw-r--r--app/controllers/follower_accounts_controller.rb11
-rw-r--r--app/controllers/following_accounts_controller.rb11
-rw-r--r--app/javascript/core/admin.js2
-rw-r--r--app/javascript/core/public.js2
-rw-r--r--app/javascript/core/settings.js2
-rw-r--r--app/javascript/flavours/glitch/packs/common.js2
-rw-r--r--app/javascript/flavours/glitch/packs/public.js2
-rw-r--r--app/javascript/flavours/glitch/packs/settings.js2
-rw-r--r--app/javascript/flavours/glitch/util/log_out.js2
-rw-r--r--app/javascript/mastodon/actions/compose.js23
-rw-r--r--app/javascript/mastodon/common.js2
-rw-r--r--app/javascript/mastodon/components/domain.js2
-rw-r--r--app/javascript/mastodon/components/scrollable_list.js20
-rw-r--r--app/javascript/mastodon/containers/domain_container.js2
-rw-r--r--app/javascript/mastodon/features/account/components/header.js4
-rw-r--r--app/javascript/mastodon/features/compose/components/action_bar.js2
-rw-r--r--app/javascript/mastodon/features/domain_blocks/index.js6
-rw-r--r--app/javascript/mastodon/features/getting_started/components/announcements.js4
-rw-r--r--app/javascript/mastodon/features/status/components/detailed_status.js2
-rw-r--r--app/javascript/mastodon/locales/defaultMessages.json16
-rw-r--r--app/javascript/mastodon/locales/en.json10
-rw-r--r--app/javascript/mastodon/utils/log_out.js2
-rw-r--r--app/javascript/packs/public.js2
-rw-r--r--app/lib/language_detector.rb4
-rw-r--r--app/models/account.rb9
-rw-r--r--app/models/account_warning_preset.rb3
-rw-r--r--app/models/admin/account_action.rb12
-rw-r--r--app/models/concerns/attachmentable.rb2
-rw-r--r--app/models/email_domain_block.rb14
-rw-r--r--app/models/media_attachment.rb110
-rw-r--r--app/models/report.rb8
-rw-r--r--app/models/status.rb2
-rw-r--r--app/serializers/rest/media_attachment_serializer.rb4
-rw-r--r--app/services/activitypub/process_account_service.rb25
-rw-r--r--app/services/fetch_resource_service.rb3
-rw-r--r--app/services/post_status_service.rb1
-rw-r--r--app/services/resolve_url_service.rb10
-rw-r--r--app/views/admin/account_actions/new.html.haml2
-rw-r--r--app/views/admin/accounts/show.html.haml13
-rw-r--r--app/views/admin/email_domain_blocks/_email_domain_block.html.haml10
-rw-r--r--app/views/admin/email_domain_blocks/new.html.haml5
-rw-r--r--app/views/admin/warning_presets/_warning_preset.html.haml10
-rw-r--r--app/views/admin/warning_presets/edit.html.haml3
-rw-r--r--app/views/admin/warning_presets/index.html.haml24
-rw-r--r--app/workers/backup_worker.rb8
-rw-r--r--app/workers/post_process_media_worker.rb34
-rw-r--r--config/application.rb1
-rw-r--r--config/deploy.rb2
-rw-r--r--config/initializers/sidekiq.rb2
-rw-r--r--config/locales/ar.yml1
-rw-r--r--config/locales/ca.yml1
-rw-r--r--config/locales/co.yml1
-rw-r--r--config/locales/cs.yml1
-rw-r--r--config/locales/cy.yml1
-rw-r--r--config/locales/da.yml1
-rw-r--r--config/locales/de.yml1
-rw-r--r--config/locales/el.yml1
-rw-r--r--config/locales/en.yml5
-rw-r--r--config/locales/en_GB.yml1
-rw-r--r--config/locales/eo.yml1
-rw-r--r--config/locales/es-AR.yml1
-rw-r--r--config/locales/es.yml1
-rw-r--r--config/locales/et.yml1
-rw-r--r--config/locales/eu.yml1
-rw-r--r--config/locales/fa.yml1
-rw-r--r--config/locales/fr.yml1
-rw-r--r--config/locales/gl.yml1
-rw-r--r--config/locales/hu.yml1
-rw-r--r--config/locales/id.yml1
-rw-r--r--config/locales/is.yml1
-rw-r--r--config/locales/it.yml1
-rw-r--r--config/locales/ja.yml1
-rw-r--r--config/locales/kab.yml1
-rw-r--r--config/locales/kk.yml1
-rw-r--r--config/locales/ko.yml1
-rw-r--r--config/locales/lt.yml1
-rw-r--r--config/locales/nl.yml1
-rw-r--r--config/locales/nn.yml1
-rw-r--r--config/locales/no.yml1
-rw-r--r--config/locales/oc.yml1
-rw-r--r--config/locales/pl.yml1
-rw-r--r--config/locales/pt-BR.yml1
-rw-r--r--config/locales/pt-PT.yml1
-rw-r--r--config/locales/ru.yml1
-rw-r--r--config/locales/simple_form.en.yml7
-rw-r--r--config/locales/sk.yml1
-rw-r--r--config/locales/sl.yml1
-rw-r--r--config/locales/sq.yml1
-rw-r--r--config/locales/sr.yml1
-rw-r--r--config/locales/sv.yml1
-rw-r--r--config/locales/th.yml1
-rw-r--r--config/locales/tr.yml1
-rw-r--r--config/locales/uk.yml1
-rw-r--r--config/locales/vi.yml1
-rw-r--r--config/locales/zh-CN.yml1
-rw-r--r--config/locales/zh-HK.yml1
-rw-r--r--config/locales/zh-TW.yml1
-rw-r--r--config/routes.rb3
-rw-r--r--db/migrate/20191212163405_add_hide_collections_to_accounts.rb5
-rw-r--r--db/migrate/20200306035625_add_processing_to_media_attachments.rb5
-rw-r--r--db/migrate/20200312144258_add_title_to_account_warning_presets.rb15
-rw-r--r--db/migrate/20200312185443_add_parent_id_to_email_domain_blocks.rb5
-rw-r--r--db/schema.rb7
-rw-r--r--lib/paperclip/attachment_extensions.rb30
-rw-r--r--lib/paperclip/video_transcoder.rb18
-rw-r--r--package.json24
-rw-r--r--spec/controllers/admin/reports_controller_spec.rb20
-rw-r--r--spec/rails_helper.rb2
-rw-r--r--yarn.lock515
119 files changed, 977 insertions, 334 deletions
diff --git a/Dockerfile b/Dockerfile
index a22efe672..77a402a32 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -4,7 +4,7 @@ FROM ubuntu:18.04 as build-dep
 SHELL ["bash", "-c"]
 
 # Install Node v12 (LTS)
-ENV NODE_VER="12.14.0"  
+ENV NODE_VER="12.16.1"
 RUN	ARCH= && \
     dpkgArch="$(dpkg --print-architecture)" && \
   case "${dpkgArch##*-}" in \
diff --git a/Gemfile b/Gemfile
index 46757eadf..d0bff213a 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 source 'https://rubygems.org'
-ruby '>= 2.4.0', '< 3.0.0'
+ruby '>= 2.5.0', '< 3.0.0'
 
 gem 'pkg-config', '~> 1.4'
 
@@ -35,7 +35,7 @@ gem 'browser'
 gem 'charlock_holmes', '~> 0.7.7'
 gem 'iso-639'
 gem 'chewy', '~> 5.1'
-gem 'cld3', '~> 3.2.6'
+gem 'cld3', '~> 3.3.0'
 gem 'devise', '~> 4.7'
 gem 'devise-two-factor', '~> 3.1'
 
@@ -84,7 +84,7 @@ gem 'mario-redis-lock', '~> 1.2', require: 'redis_lock'
 gem 'rqrcode', '~> 1.1'
 gem 'ruby-progressbar', '~> 1.10'
 gem 'sanitize', '~> 5.1'
-gem 'sidekiq', '~> 5.2'
+gem 'sidekiq', '~> 6.0'
 gem 'sidekiq-scheduler', '~> 3.0'
 gem 'sidekiq-unique-jobs', '~> 6.0'
 gem 'sidekiq-bulk', '~>0.2.0'
@@ -145,7 +145,7 @@ group :development do
   gem 'brakeman', '~> 4.7', require: false
   gem 'bundler-audit', '~> 0.6', require: false
 
-  gem 'capistrano', '~> 3.11'
+  gem 'capistrano', '~> 3.12'
   gem 'capistrano-rails', '~> 1.4'
   gem 'capistrano-rbenv', '~> 2.1'
   gem 'capistrano-yarn', '~> 2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 49b2a8fe8..48915ab7c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -128,7 +128,7 @@ GEM
       bundler (>= 1.2.0, < 3)
       thor (~> 0.18)
     byebug (11.1.1)
-    capistrano (3.11.2)
+    capistrano (3.12.1)
       airbrussh (>= 1.0.0)
       i18n
       rake (>= 10.0.0)
@@ -160,7 +160,7 @@ GEM
       elasticsearch (>= 2.0.0)
       elasticsearch-dsl
     chunky_png (1.3.11)
-    cld3 (3.2.6)
+    cld3 (3.3.0)
       ffi (>= 1.1.0, < 1.12.0)
     climate_control (0.2.0)
     cocaine (0.5.8)
@@ -214,7 +214,7 @@ GEM
     encryptor (3.0.0)
     equatable (0.6.1)
     erubi (1.9.0)
-    et-orbi (1.1.6)
+    et-orbi (1.2.3)
       tzinfo
     excon (0.71.0)
     fabrication (2.21.0)
@@ -241,8 +241,8 @@ GEM
       fog-json (>= 1.0)
       ipaddress (>= 0.8)
     formatador (0.2.5)
-    fugit (1.1.6)
-      et-orbi (~> 1.1, >= 1.1.6)
+    fugit (1.3.3)
+      et-orbi (~> 1.1, >= 1.1.8)
       raabro (~> 1.1)
     fuubar (2.5.0)
       rspec-core (~> 3.0)
@@ -265,8 +265,8 @@ GEM
       railties (>= 4.0.1)
     hamster (3.0.0)
       concurrent-ruby (~> 1.0)
-    hashdiff (1.0.0)
-    hashie (3.6.0)
+    hashdiff (1.0.1)
+    hashie (4.1.0)
     highline (2.0.3)
     hiredis (0.6.3)
     hkdf (0.3.0)
@@ -304,9 +304,9 @@ GEM
     jmespath (1.4.0)
     json (2.3.0)
     json-canonicalization (0.2.0)
-    json-ld (3.1.0)
+    json-ld (3.1.1)
       htmlentities (~> 4.3)
-      json-canonicalization (~> 0.1)
+      json-canonicalization (~> 0.2)
       link_header (~> 0.0, >= 0.0.8)
       multi_json (~> 1.14)
       rack (~> 2.0)
@@ -384,8 +384,8 @@ GEM
       sidekiq (>= 3.5)
       statsd-ruby (~> 1.4, >= 1.4.0)
     oj (3.10.3)
-    omniauth (1.9.0)
-      hashie (>= 3.4.6, < 3.7.0)
+    omniauth (1.9.1)
+      hashie (>= 3.4.6)
       rack (>= 1.6.2, < 3)
     omniauth-cas (1.1.1)
       addressable (~> 2.3)
@@ -445,7 +445,7 @@ GEM
       rack (>= 1.0, < 3)
     rack-cors (1.1.1)
       rack (>= 2.0.0)
-    rack-protection (2.0.7)
+    rack-protection (2.0.8.1)
       rack
     rack-proxy (0.6.5)
       rack
@@ -556,32 +556,34 @@ GEM
     ruby-progressbar (1.10.1)
     ruby-saml (1.9.0)
       nokogiri (>= 1.5.10)
-    rufus-scheduler (3.5.2)
-      fugit (~> 1.1, >= 1.1.5)
+    rufus-scheduler (3.6.0)
+      fugit (~> 1.1, >= 1.1.6)
     safe_yaml (1.0.5)
     sanitize (5.1.0)
       crass (~> 1.0.2)
       nokogiri (>= 1.8.0)
       nokogumbo (~> 2.0)
-    sidekiq (5.2.7)
-      connection_pool (~> 2.2, >= 2.2.2)
-      rack (>= 1.5.0)
-      rack-protection (>= 1.5.0)
-      redis (>= 3.3.5, < 5)
+    sidekiq (6.0.4)
+      connection_pool (>= 2.2.2)
+      rack (>= 2.0.0)
+      rack-protection (>= 2.0.0)
+      redis (>= 4.1.0)
     sidekiq-bulk (0.2.0)
       sidekiq
-    sidekiq-scheduler (3.0.0)
+    sidekiq-scheduler (3.0.1)
+      e2mmap
       redis (>= 3, < 5)
       rufus-scheduler (~> 3.2)
       sidekiq (>= 3)
+      thwait
       tilt (>= 1.4.0)
-    sidekiq-unique-jobs (6.0.18)
+    sidekiq-unique-jobs (6.0.20)
       concurrent-ruby (~> 1.0, >= 1.0.5)
       sidekiq (>= 4.0, < 7.0)
       thor (~> 0)
     simple-navigation (4.1.0)
       activesupport (>= 2.3.2)
-    simple_form (5.0.1)
+    simple_form (5.0.2)
       actionpack (>= 5.0)
       activemodel (>= 5.0)
     simplecov (0.18.2)
@@ -595,7 +597,7 @@ GEM
       actionpack (>= 4.0)
       activesupport (>= 4.0)
       sprockets (>= 3.0.0)
-    sshkit (1.20.0)
+    sshkit (1.21.0)
       net-scp (>= 1.1.2)
       net-ssh (>= 2.8.0)
     stackprof (0.2.15)
@@ -640,7 +642,7 @@ GEM
     uniform_notifier (1.13.0)
     warden (1.2.8)
       rack (>= 2.0.6)
-    webmock (3.8.0)
+    webmock (3.8.3)
       addressable (>= 2.3.6)
       crack (>= 0.3.2)
       hashdiff (>= 0.4.0, < 2.0.0)
@@ -675,14 +677,14 @@ DEPENDENCIES
   browser
   bullet (~> 6.1)
   bundler-audit (~> 0.6)
-  capistrano (~> 3.11)
+  capistrano (~> 3.12)
   capistrano-rails (~> 1.4)
   capistrano-rbenv (~> 2.1)
   capistrano-yarn (~> 2.0)
   capybara (~> 3.31)
   charlock_holmes (~> 0.7.7)
   chewy (~> 5.1)
-  cld3 (~> 3.2.6)
+  cld3 (~> 3.3.0)
   climate_control (~> 0.2)
   concurrent-ruby
   connection_pool
@@ -767,7 +769,7 @@ DEPENDENCIES
   rubocop-rails (~> 2.4)
   ruby-progressbar (~> 1.10)
   sanitize (~> 5.1)
-  sidekiq (~> 5.2)
+  sidekiq (~> 6.0)
   sidekiq-bulk (~> 0.2.0)
   sidekiq-scheduler (~> 3.0)
   sidekiq-unique-jobs (~> 6.0)
diff --git a/app/chewy/statuses_index.rb b/app/chewy/statuses_index.rb
index f5735421c..bec9ed88b 100644
--- a/app/chewy/statuses_index.rb
+++ b/app/chewy/statuses_index.rb
@@ -47,6 +47,11 @@ class StatusesIndex < Chewy::Index
       data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
     end
 
+    crutch :bookmarks do |collection|
+      data = ::Bookmark.where(status_id: collection.map(&:id)).where(account: Account.local).pluck(:status_id, :account_id)
+      data.each.with_object({}) { |(id, name), result| (result[id] ||= []).push(name) }
+    end
+
     root date_detection: false do
       field :id, type: 'long'
       field :account_id, type: 'long'
diff --git a/app/controllers/admin/email_domain_blocks_controller.rb b/app/controllers/admin/email_domain_blocks_controller.rb
index 9fe85064e..c25919726 100644
--- a/app/controllers/admin/email_domain_blocks_controller.rb
+++ b/app/controllers/admin/email_domain_blocks_controller.rb
@@ -6,12 +6,12 @@ module Admin
 
     def index
       authorize :email_domain_block, :index?
-      @email_domain_blocks = EmailDomainBlock.page(params[:page])
+      @email_domain_blocks = EmailDomainBlock.where(parent_id: nil).includes(:children).order(id: :desc).page(params[:page])
     end
 
     def new
       authorize :email_domain_block, :create?
-      @email_domain_block = EmailDomainBlock.new
+      @email_domain_block = EmailDomainBlock.new(domain: params[:_domain])
     end
 
     def create
@@ -21,6 +21,28 @@ module Admin
 
       if @email_domain_block.save
         log_action :create, @email_domain_block
+
+        if @email_domain_block.with_dns_records?
+          hostnames = []
+          ips       = []
+
+          Resolv::DNS.open do |dns|
+            dns.timeouts = 1
+
+            hostnames = dns.getresources(@email_domain_block.domain, Resolv::DNS::Resource::IN::MX).to_a.map { |e| e.exchange.to_s }
+
+            ([@email_domain_block.domain] + hostnames).uniq.each do |hostname|
+              ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::A).to_a.map { |e| e.address.to_s })
+              ips.concat(dns.getresources(hostname, Resolv::DNS::Resource::IN::AAAA).to_a.map { |e| e.address.to_s })
+            end
+          end
+
+          (hostnames + ips).each do |hostname|
+            another_email_domain_block = EmailDomainBlock.new(domain: hostname, parent: @email_domain_block)
+            log_action :create, another_email_domain_block if another_email_domain_block.save
+          end
+        end
+
         redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.created_msg')
       else
         render :new
@@ -41,7 +63,7 @@ module Admin
     end
 
     def resource_params
-      params.require(:email_domain_block).permit(:domain)
+      params.require(:email_domain_block).permit(:domain, :with_dns_records)
     end
   end
 end
diff --git a/app/controllers/admin/warning_presets_controller.rb b/app/controllers/admin/warning_presets_controller.rb
index 37be842c5..b376f8d9b 100644
--- a/app/controllers/admin/warning_presets_controller.rb
+++ b/app/controllers/admin/warning_presets_controller.rb
@@ -7,7 +7,7 @@ module Admin
     def index
       authorize :account_warning_preset, :index?
 
-      @warning_presets = AccountWarningPreset.all
+      @warning_presets = AccountWarningPreset.alphabetic
       @warning_preset  = AccountWarningPreset.new
     end
 
@@ -19,7 +19,7 @@ module Admin
       if @warning_preset.save
         redirect_to admin_warning_presets_path
       else
-        @warning_presets = AccountWarningPreset.all
+        @warning_presets = AccountWarningPreset.alphabetic
         render :index
       end
     end
@@ -52,7 +52,7 @@ module Admin
     end
 
     def warning_preset_params
-      params.require(:account_warning_preset).permit(:text)
+      params.require(:account_warning_preset).permit(:title, :text)
     end
   end
 end
diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb
index 850702cca..1daa1ed0d 100644
--- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb
+++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb
@@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController
   end
 
   def hide_results?
-    (@account.user_hides_network? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
+    (@account.hides_followers? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
   end
 
   def default_accounts
diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb
index 830dcd8a1..6fc23cf75 100644
--- a/app/controllers/api/v1/accounts/following_accounts_controller.rb
+++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb
@@ -25,7 +25,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController
   end
 
   def hide_results?
-    (@account.user_hides_network? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
+    (@account.hides_following? && current_account&.id != @account.id) || (current_account && @account.blocking?(current_account))
   end
 
   def default_accounts
diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb
index d87d7b946..0bb3d0d27 100644
--- a/app/controllers/api/v1/media_controller.rb
+++ b/app/controllers/api/v1/media_controller.rb
@@ -3,25 +3,42 @@
 class Api::V1::MediaController < Api::BaseController
   before_action -> { doorkeeper_authorize! :write, :'write:media' }
   before_action :require_user!
+  before_action :set_media_attachment, except: [:create]
+  before_action :check_processing, except: [:create]
 
   def create
-    @media = current_account.media_attachments.create!(media_params)
-    render json: @media, serializer: REST::MediaAttachmentSerializer
+    @media_attachment = current_account.media_attachments.create!(media_attachment_params)
+    render json: @media_attachment, serializer: REST::MediaAttachmentSerializer
   rescue Paperclip::Errors::NotIdentifiedByImageMagickError
     render json: file_type_error, status: 422
   rescue Paperclip::Error
     render json: processing_error, status: 500
   end
 
+  def show
+    render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
+  end
+
   def update
-    @media = current_account.media_attachments.where(status_id: nil).find(params[:id])
-    @media.update!(media_params)
-    render json: @media, serializer: REST::MediaAttachmentSerializer
+    @media_attachment.update!(media_attachment_params)
+    render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: status_code_for_media_attachment
   end
 
   private
 
-  def media_params
+  def status_code_for_media_attachment
+    @media_attachment.not_processed? ? 206 : 200
+  end
+
+  def set_media_attachment
+    @media_attachment = current_account.media_attachments.unattached.find(params[:id])
+  end
+
+  def check_processing
+    render json: processing_error, status: 422 if @media_attachment.processing_failed?
+  end
+
+  def media_attachment_params
     params.permit(:file, :description, :focus)
   end
 
diff --git a/app/controllers/api/v2/media_controller.rb b/app/controllers/api/v2/media_controller.rb
new file mode 100644
index 000000000..0c1baf01d
--- /dev/null
+++ b/app/controllers/api/v2/media_controller.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class Api::V2::MediaController < Api::V1::MediaController
+  def create
+    @media_attachment = current_account.media_attachments.create!({ delay_processing: true }.merge(media_attachment_params))
+    render json: @media_attachment, serializer: REST::MediaAttachmentSerializer, status: 202
+  rescue Paperclip::Errors::NotIdentifiedByImageMagickError
+    render json: file_type_error, status: 422
+  rescue Paperclip::Error
+    render json: processing_error, status: 500
+  end
+end
diff --git a/app/controllers/follower_accounts_controller.rb b/app/controllers/follower_accounts_controller.rb
index a5dfffd6d..eb223c3f7 100644
--- a/app/controllers/follower_accounts_controller.rb
+++ b/app/controllers/follower_accounts_controller.rb
@@ -29,7 +29,8 @@ class FollowerAccountsController < ApplicationController
         render json: collection_presenter,
                serializer: ActivityPub::CollectionSerializer,
                adapter: ActivityPub::Adapter,
-               content_type: 'application/activity+json'
+               content_type: 'application/activity+json',
+               fields: restrict_fields_to
       end
     end
   end
@@ -72,4 +73,12 @@ class FollowerAccountsController < ApplicationController
       )
     end
   end
+
+  def restrict_fields_to
+    if page_requested? || !@account.user_hides_network?
+      # Return all fields
+    else
+      %i(id type totalItems)
+    end
+  end
 end
diff --git a/app/controllers/following_accounts_controller.rb b/app/controllers/following_accounts_controller.rb
index ff23d97f9..4ddccf607 100644
--- a/app/controllers/following_accounts_controller.rb
+++ b/app/controllers/following_accounts_controller.rb
@@ -29,7 +29,8 @@ class FollowingAccountsController < ApplicationController
         render json: collection_presenter,
                serializer: ActivityPub::CollectionSerializer,
                adapter: ActivityPub::Adapter,
-               content_type: 'application/activity+json'
+               content_type: 'application/activity+json',
+               fields: restrict_fields_to
       end
     end
   end
@@ -72,4 +73,12 @@ class FollowingAccountsController < ApplicationController
       )
     end
   end
+
+  def restrict_fields_to
+    if page_requested? || !@account.user_hides_network?
+      # Return all fields
+    else
+      %i(id type totalItems)
+    end
+  end
 end
diff --git a/app/javascript/core/admin.js b/app/javascript/core/admin.js
index e4d683dd0..09da9efd3 100644
--- a/app/javascript/core/admin.js
+++ b/app/javascript/core/admin.js
@@ -1,6 +1,6 @@
 //  This file will be loaded on admin pages, regardless of theme.
 
-import { delegate } from 'rails-ujs';
+import { delegate } from '@rails/ujs';
 import ready from '../mastodon/ready';
 
 const batchCheckboxClassName = '.batch-checkbox input[type="checkbox"]';
diff --git a/app/javascript/core/public.js b/app/javascript/core/public.js
index 0f4222139..344c05181 100644
--- a/app/javascript/core/public.js
+++ b/app/javascript/core/public.js
@@ -3,7 +3,7 @@
 import createHistory from 'history/createBrowserHistory';
 import ready from '../mastodon/ready';
 
-const { delegate } = require('rails-ujs');
+const { delegate } = require('@rails/ujs');
 const { length } = require('stringz');
 
 delegate(document, '.webapp-btn', 'click', ({ target, button }) => {
diff --git a/app/javascript/core/settings.js b/app/javascript/core/settings.js
index e0cb944e0..e02c91cc7 100644
--- a/app/javascript/core/settings.js
+++ b/app/javascript/core/settings.js
@@ -1,7 +1,7 @@
 //  This file will be loaded on settings pages, regardless of theme.
 
 import escapeTextContentForBrowser from 'escape-html';
-const { delegate } = require('rails-ujs');
+const { delegate } = require('@rails/ujs');
 import emojify from '../mastodon/features/emoji/emoji';
 
 delegate(document, '#account_display_name', 'input', ({ target }) => {
diff --git a/app/javascript/flavours/glitch/packs/common.js b/app/javascript/flavours/glitch/packs/common.js
index 94a4e6ee4..1fedc890a 100644
--- a/app/javascript/flavours/glitch/packs/common.js
+++ b/app/javascript/flavours/glitch/packs/common.js
@@ -1,4 +1,4 @@
-import { start } from 'rails-ujs';
+import { start } from '@rails/ujs';
 
 start();
 
diff --git a/app/javascript/flavours/glitch/packs/public.js b/app/javascript/flavours/glitch/packs/public.js
index d8a97704f..066479fa6 100644
--- a/app/javascript/flavours/glitch/packs/public.js
+++ b/app/javascript/flavours/glitch/packs/public.js
@@ -5,7 +5,7 @@ import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extension
 function main() {
   const IntlMessageFormat = require('intl-messageformat').default;
   const { timeAgoString } = require('flavours/glitch/components/relative_timestamp');
-  const { delegate } = require('rails-ujs');
+  const { delegate } = require('@rails/ujs');
   const emojify = require('flavours/glitch/util/emoji').default;
   const { getLocale } = require('locales');
   const { messages } = getLocale();
diff --git a/app/javascript/flavours/glitch/packs/settings.js b/app/javascript/flavours/glitch/packs/settings.js
index edf1b82e0..8a9f23505 100644
--- a/app/javascript/flavours/glitch/packs/settings.js
+++ b/app/javascript/flavours/glitch/packs/settings.js
@@ -3,7 +3,7 @@ import ready from 'flavours/glitch/util/ready';
 import loadKeyboardExtensions from 'flavours/glitch/util/load_keyboard_extensions';
 
 function main() {
-  const { delegate } = require('rails-ujs');
+  const { delegate } = require('@rails/ujs');
 
   delegate(document, '.sidebar__toggle__icon', 'click', () => {
     const target = document.querySelector('.sidebar ul');
diff --git a/app/javascript/flavours/glitch/util/log_out.js b/app/javascript/flavours/glitch/util/log_out.js
index 8e1659293..42dcee03e 100644
--- a/app/javascript/flavours/glitch/util/log_out.js
+++ b/app/javascript/flavours/glitch/util/log_out.js
@@ -1,4 +1,4 @@
-import Rails from 'rails-ujs';
+import Rails from '@rails/ujs';
 import { signOutLink } from 'flavours/glitch/util/backend_links';
 
 export const logOut = () => {
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js
index c3c6ff1a1..6b73fc90e 100644
--- a/app/javascript/mastodon/actions/compose.js
+++ b/app/javascript/mastodon/actions/compose.js
@@ -230,12 +230,31 @@ export function uploadCompose(files) {
         // Account for disparity in size of original image and resized data
         total += file.size - f.size;
 
-        return api(getState).post('/api/v1/media', data, {
+        return api(getState).post('/api/v2/media', data, {
           onUploadProgress: function({ loaded }){
             progress[i] = loaded;
             dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
           },
-        }).then(({ data }) => dispatch(uploadComposeSuccess(data, f)));
+        }).then(({ status, data }) => {
+          // If server-side processing of the media attachment has not completed yet,
+          // poll the server until it is, before showing the media attachment as uploaded
+
+          if (status === 200) {
+            dispatch(uploadComposeSuccess(data, f));
+          } else if (status === 202) {
+            const poll = () => {
+              api(getState).get(`/api/v1/media/${data.id}`).then(response => {
+                if (response.status === 200) {
+                  dispatch(uploadComposeSuccess(response.data, f));
+                } else if (response.status === 206) {
+                  setTimeout(() => poll(), 1000);
+                }
+              }).catch(error => dispatch(uploadComposeFail(error)));
+            };
+
+            poll();
+          }
+        });
       }).catch(error => dispatch(uploadComposeFail(error)));
     };
   };
diff --git a/app/javascript/mastodon/common.js b/app/javascript/mastodon/common.js
index fba21316a..6818aa5d5 100644
--- a/app/javascript/mastodon/common.js
+++ b/app/javascript/mastodon/common.js
@@ -1,4 +1,4 @@
-import Rails from 'rails-ujs';
+import Rails from '@rails/ujs';
 
 export function start() {
   require('font-awesome/css/font-awesome.css');
diff --git a/app/javascript/mastodon/components/domain.js b/app/javascript/mastodon/components/domain.js
index 85729ca94..697065d87 100644
--- a/app/javascript/mastodon/components/domain.js
+++ b/app/javascript/mastodon/components/domain.js
@@ -5,7 +5,7 @@ import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
 const messages = defineMessages({
-  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
+  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
 });
 
 export default @injectIntl
diff --git a/app/javascript/mastodon/components/scrollable_list.js b/app/javascript/mastodon/components/scrollable_list.js
index 3a490e78e..65ca43911 100644
--- a/app/javascript/mastodon/components/scrollable_list.js
+++ b/app/javascript/mastodon/components/scrollable_list.js
@@ -82,15 +82,19 @@ export default class ScrollableList extends PureComponent {
   lastScrollWasSynthetic = false;
   scrollToTopOnMouseIdle = false;
 
+  _getScrollingElement = () => {
+    if (this.props.bindToDocument) {
+      return (document.scrollingElement || document.body);
+    } else {
+      return this.node;
+    }
+  }
+
   setScrollTop = newScrollTop => {
     if (this.getScrollTop() !== newScrollTop) {
       this.lastScrollWasSynthetic = true;
 
-      if (this.props.bindToDocument) {
-        document.scrollingElement.scrollTop = newScrollTop;
-      } else {
-        this.node.scrollTop = newScrollTop;
-      }
+      this._getScrollingElement().scrollTop = newScrollTop;
     }
   };
 
@@ -151,15 +155,15 @@ export default class ScrollableList extends PureComponent {
   }
 
   getScrollTop = () => {
-    return this.props.bindToDocument ? document.scrollingElement.scrollTop : this.node.scrollTop;
+    return this._getScrollingElement().scrollTop;
   }
 
   getScrollHeight = () => {
-    return this.props.bindToDocument ? document.scrollingElement.scrollHeight : this.node.scrollHeight;
+    return this._getScrollingElement().scrollHeight;
   }
 
   getClientHeight = () => {
-    return this.props.bindToDocument ? document.scrollingElement.clientHeight : this.node.clientHeight;
+    return this._getScrollingElement().clientHeight;
   }
 
   updateScrollBottom = (snapshot) => {
diff --git a/app/javascript/mastodon/containers/domain_container.js b/app/javascript/mastodon/containers/domain_container.js
index 813178bbf..8a8ba1df1 100644
--- a/app/javascript/mastodon/containers/domain_container.js
+++ b/app/javascript/mastodon/containers/domain_container.js
@@ -6,7 +6,7 @@ import Domain from '../components/domain';
 import { openModal } from '../actions/modal';
 
 const messages = defineMessages({
-  blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
+  blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Block entire domain' },
 });
 
 const makeMapStateToProps = () => {
diff --git a/app/javascript/mastodon/features/account/components/header.js b/app/javascript/mastodon/features/account/components/header.js
index 35cc3952f..92780a70b 100644
--- a/app/javascript/mastodon/features/account/components/header.js
+++ b/app/javascript/mastodon/features/account/components/header.js
@@ -39,7 +39,7 @@ const messages = defineMessages({
   favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
   lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
   blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
-  domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
+  domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Blocked domains' },
   mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
   endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
   unendorse: { id: 'account.unendorse', defaultMessage: 'Don\'t feature on profile' },
@@ -142,7 +142,7 @@ class Header extends ImmutablePureComponent {
     if (me !== account.get('id') && account.getIn(['relationship', 'muting'])) {
       info.push(<span key='muted' className='relationship-tag'><FormattedMessage id='account.muted' defaultMessage='Muted' /></span>);
     } else if (me !== account.get('id') && account.getIn(['relationship', 'domain_blocking'])) {
-      info.push(<span key='domain_blocked' className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain hidden' /></span>);
+      info.push(<span key='domain_blocked' className='relationship-tag'><FormattedMessage id='account.domain_blocked' defaultMessage='Domain blocked' /></span>);
     }
 
     if (me !== account.get('id')) {
diff --git a/app/javascript/mastodon/features/compose/components/action_bar.js b/app/javascript/mastodon/features/compose/components/action_bar.js
index dd2632796..07d92bb7e 100644
--- a/app/javascript/mastodon/features/compose/components/action_bar.js
+++ b/app/javascript/mastodon/features/compose/components/action_bar.js
@@ -16,6 +16,7 @@ const messages = defineMessages({
   mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
   filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
   logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
+  bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
 });
 
 export default @injectIntl
@@ -42,6 +43,7 @@ class ActionBar extends React.PureComponent {
     menu.push(null);
     menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
     menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
+    menu.push({ text: intl.formatMessage(messages.bookmarks), to: '/bookmarks' });
     menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
     menu.push(null);
     menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
diff --git a/app/javascript/mastodon/features/domain_blocks/index.js b/app/javascript/mastodon/features/domain_blocks/index.js
index 06533d5ac..a6d988912 100644
--- a/app/javascript/mastodon/features/domain_blocks/index.js
+++ b/app/javascript/mastodon/features/domain_blocks/index.js
@@ -13,8 +13,8 @@ import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_bloc
 import ScrollableList from '../../components/scrollable_list';
 
 const messages = defineMessages({
-  heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
-  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
+  heading: { id: 'column.domain_blocks', defaultMessage: 'Blocked domains' },
+  unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unblock domain {domain}' },
 });
 
 const mapStateToProps = state => ({
@@ -55,7 +55,7 @@ class Blocks extends ImmutablePureComponent {
       );
     }
 
-    const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
+    const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no blocked domains yet.' />;
 
     return (
       <Column bindToDocument={!multiColumn} icon='minus-circle' heading={intl.formatMessage(messages.heading)}>
diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.js b/app/javascript/mastodon/features/getting_started/components/announcements.js
index fb4a6bf0d..ec57c41b2 100644
--- a/app/javascript/mastodon/features/getting_started/components/announcements.js
+++ b/app/javascript/mastodon/features/getting_started/components/announcements.js
@@ -389,7 +389,7 @@ class Announcements extends ImmutablePureComponent {
   _markAnnouncementAsRead () {
     const { dismissAnnouncement, announcements } = this.props;
     const { index } = this.state;
-    const announcement = announcements.get(index);
+    const announcement = announcements.get(index) || announcements.get(index - 1);
     if (!announcement.get('read')) dismissAnnouncement(announcement.get('id'));
   }
 
@@ -407,7 +407,7 @@ class Announcements extends ImmutablePureComponent {
 
   render () {
     const { announcements, intl } = this.props;
-    const { index } = this.state;
+    const index = this.state.index < announcements.size ? this.state.index : announcements.size - 1;
 
     if (announcements.isEmpty()) {
       return null;
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.js b/app/javascript/mastodon/features/status/components/detailed_status.js
index 2fec247c1..7a82fa13a 100644
--- a/app/javascript/mastodon/features/status/components/detailed_status.js
+++ b/app/javascript/mastodon/features/status/components/detailed_status.js
@@ -166,7 +166,7 @@ export default class DetailedStatus extends ImmutablePureComponent {
       reblogIcon = 'lock';
     }
 
-    if (status.get('visibility') === 'private') {
+    if (['private', 'direct'].includes(status.get('visibility'))) {
       reblogLink = <Icon id={reblogIcon} />;
     } else if (this.context.router) {
       reblogLink = (
diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json
index 93cfa2431..225b7ade2 100644
--- a/app/javascript/mastodon/locales/defaultMessages.json
+++ b/app/javascript/mastodon/locales/defaultMessages.json
@@ -523,7 +523,7 @@
   {
     "descriptors": [
       {
-        "defaultMessage": "Hide entire domain",
+        "defaultMessage": "Block entire domain",
         "id": "confirmations.domain_block.confirm"
       },
       {
@@ -737,7 +737,7 @@
         "id": "navigation_bar.blocks"
       },
       {
-        "defaultMessage": "Hidden domains",
+        "defaultMessage": "Blocked domains",
         "id": "navigation_bar.domain_blocks"
       },
       {
@@ -773,7 +773,7 @@
         "id": "account.muted"
       },
       {
-        "defaultMessage": "Domain hidden",
+        "defaultMessage": "Domain blocked",
         "id": "account.domain_blocked"
       },
       {
@@ -917,6 +917,10 @@
       {
         "defaultMessage": "Logout",
         "id": "navigation_bar.logout"
+      },
+      {
+        "defaultMessage": "Bookmarks",
+        "id": "navigation_bar.bookmarks"
       }
     ],
     "path": "app/javascript/mastodon/features/compose/components/action_bar.json"
@@ -1466,7 +1470,7 @@
   {
     "descriptors": [
       {
-        "defaultMessage": "Hidden domains",
+        "defaultMessage": "Blocked domains",
         "id": "column.domain_blocks"
       },
       {
@@ -1474,7 +1478,7 @@
         "id": "account.unblock_domain"
       },
       {
-        "defaultMessage": "There are no hidden domains yet.",
+        "defaultMessage": "There are no blocked domains yet.",
         "id": "empty_column.domain_blocks"
       }
     ],
@@ -2957,4 +2961,4 @@
     ],
     "path": "app/javascript/mastodon/features/video/index.json"
   }
-]
+]
\ No newline at end of file
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index 3ec951903..703bbcaac 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -7,7 +7,7 @@
   "account.blocked": "Blocked",
   "account.cancel_follow_request": "Cancel follow request",
   "account.direct": "Direct message @{name}",
-  "account.domain_blocked": "Domain hidden",
+  "account.domain_blocked": "Domain blocked",
   "account.edit_profile": "Edit profile",
   "account.endorse": "Feature on profile",
   "account.follow": "Follow",
@@ -57,7 +57,7 @@
   "column.community": "Local timeline",
   "column.direct": "Direct messages",
   "column.directory": "Browse profiles",
-  "column.domain_blocks": "Hidden domains",
+  "column.domain_blocks": "Blocked domains",
   "column.favourites": "Favourites",
   "column.follow_requests": "Follow requests",
   "column.home": "Home",
@@ -107,7 +107,7 @@
   "confirmations.delete.message": "Are you sure you want to delete this status?",
   "confirmations.delete_list.confirm": "Delete",
   "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
-  "confirmations.domain_block.confirm": "Hide entire domain",
+  "confirmations.domain_block.confirm": "Block entire domain",
   "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
   "confirmations.logout.confirm": "Log out",
   "confirmations.logout.message": "Are you sure you want to log out?",
@@ -150,7 +150,7 @@
   "empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.",
   "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
   "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
-  "empty_column.domain_blocks": "There are no hidden domains yet.",
+  "empty_column.domain_blocks": "There are no blocked domains yet.",
   "empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
   "empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
   "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
@@ -269,7 +269,7 @@
   "navigation_bar.compose": "Compose new toot",
   "navigation_bar.direct": "Direct messages",
   "navigation_bar.discover": "Discover",
-  "navigation_bar.domain_blocks": "Hidden domains",
+  "navigation_bar.domain_blocks": "Blocked domains",
   "navigation_bar.edit_profile": "Edit profile",
   "navigation_bar.favourites": "Favourites",
   "navigation_bar.filters": "Muted words",
diff --git a/app/javascript/mastodon/utils/log_out.js b/app/javascript/mastodon/utils/log_out.js
index b43417f4b..3a4cc8ecb 100644
--- a/app/javascript/mastodon/utils/log_out.js
+++ b/app/javascript/mastodon/utils/log_out.js
@@ -1,4 +1,4 @@
-import Rails from 'rails-ujs';
+import Rails from '@rails/ujs';
 
 export const logOut = () => {
   const form = document.createElement('form');
diff --git a/app/javascript/packs/public.js b/app/javascript/packs/public.js
index 13cb5d548..dc85164d0 100644
--- a/app/javascript/packs/public.js
+++ b/app/javascript/packs/public.js
@@ -8,7 +8,7 @@ start();
 function main() {
   const IntlMessageFormat = require('intl-messageformat').default;
   const { timeAgoString } = require('../mastodon/components/relative_timestamp');
-  const { delegate } = require('rails-ujs');
+  const { delegate } = require('@rails/ujs');
   const emojify = require('../mastodon/features/emoji/emoji').default;
   const { getLocale } = require('../mastodon/locales');
   const { messages } = getLocale();
diff --git a/app/lib/language_detector.rb b/app/lib/language_detector.rb
index 302072bcc..05a06726d 100644
--- a/app/lib/language_detector.rb
+++ b/app/lib/language_detector.rb
@@ -52,8 +52,10 @@ class LanguageDetector
 
   def detect_language_code(text)
     return if unreliable_input?(text)
+
     result = @identifier.find_language(text)
-    iso6391(result.language.to_s).to_sym if result.reliable?
+
+    iso6391(result.language.to_s).to_sym if result&.reliable?
   end
 
   def iso6391(bcp47)
diff --git a/app/models/account.rb b/app/models/account.rb
index 73421ee5a..82d4d10de 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -46,6 +46,7 @@
 #  silenced_at             :datetime
 #  suspended_at            :datetime
 #  trust_level             :integer
+#  hide_collections        :boolean
 #
 
 class Account < ApplicationRecord
@@ -325,6 +326,14 @@ class Account < ApplicationRecord
     save!
   end
 
+  def hides_followers?
+    hide_collections? || user_hides_network?
+  end
+
+  def hides_following?
+    hide_collections? || user_hides_network?
+  end
+
   def object_type
     :person
   end
diff --git a/app/models/account_warning_preset.rb b/app/models/account_warning_preset.rb
index ba8ceabb3..c20f683cf 100644
--- a/app/models/account_warning_preset.rb
+++ b/app/models/account_warning_preset.rb
@@ -8,8 +8,11 @@
 #  text       :text             default(""), not null
 #  created_at :datetime         not null
 #  updated_at :datetime         not null
+#  title      :string           default(""), not null
 #
 
 class AccountWarningPreset < ApplicationRecord
   validates :text, presence: true
+
+  scope :alphabetic, -> { order(title: :asc, text: :asc) }
 end
diff --git a/app/models/admin/account_action.rb b/app/models/admin/account_action.rb
index e9da003a3..b30a82369 100644
--- a/app/models/admin/account_action.rb
+++ b/app/models/admin/account_action.rb
@@ -62,8 +62,6 @@ class Admin::AccountAction
 
   def process_action!
     case type
-    when 'none'
-      handle_resolve!
     when 'disable'
       handle_disable!
     when 'silence'
@@ -105,16 +103,6 @@ class Admin::AccountAction
     end
   end
 
-  def handle_resolve!
-    if with_report? && report.account_id == -99 && target_account.trust_level == Account::TRUST_LEVELS[:untrusted]
-      # This is an automated report and it is being dismissed, so it's
-      # a false positive, in which case update the account's trust level
-      # to prevent further spam checks
-
-      target_account.update(trust_level: Account::TRUST_LEVELS[:trusted])
-    end
-  end
-
   def handle_disable!
     authorize(target_account.user, :disable?)
     log_action(:disable, target_account.user)
diff --git a/app/models/concerns/attachmentable.rb b/app/models/concerns/attachmentable.rb
index 43ff8ac12..18b872c1e 100644
--- a/app/models/concerns/attachmentable.rb
+++ b/app/models/concerns/attachmentable.rb
@@ -74,7 +74,7 @@ module Attachmentable
     self.class.attachment_definitions.each_key do |attachment_name|
       attachment = send(attachment_name)
 
-      next if attachment.blank? || attachment.queued_for_write[:original].blank?
+      next if attachment.blank? || attachment.queued_for_write[:original].blank? || attachment.options[:preserve_files]
 
       attachment.instance_write :file_name, SecureRandom.hex(8) + File.extname(attachment.instance_read(:file_name))
     end
diff --git a/app/models/email_domain_block.rb b/app/models/email_domain_block.rb
index bc70dea25..f50fa46ba 100644
--- a/app/models/email_domain_block.rb
+++ b/app/models/email_domain_block.rb
@@ -7,13 +7,27 @@
 #  domain     :string           default(""), not null
 #  created_at :datetime         not null
 #  updated_at :datetime         not null
+#  parent_id  :bigint(8)
 #
 
 class EmailDomainBlock < ApplicationRecord
   include DomainNormalizable
 
+  belongs_to :parent, class_name: 'EmailDomainBlock', optional: true
+  has_many :children, class_name: 'EmailDomainBlock', foreign_key: :parent_id, inverse_of: :parent, dependent: :destroy
+
   validates :domain, presence: true, uniqueness: true, domain: true
 
+  def with_dns_records=(val)
+    @with_dns_records = ActiveModel::Type::Boolean.new.cast(val)
+  end
+
+  def with_dns_records?
+    @with_dns_records
+  end
+
+  alias with_dns_records with_dns_records?
+
   def self.block?(email)
     _, domain = email.split('@', 2)
 
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index 2813d9200..59427a8cc 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -19,12 +19,14 @@
 #  description         :text
 #  scheduled_status_id :bigint(8)
 #  blurhash            :string
+#  processing          :integer
 #
 
 class MediaAttachment < ApplicationRecord
   self.inheritance_column = nil
 
   enum type: [:image, :gifv, :video, :unknown, :audio]
+  enum processing: [:queued, :in_progress, :complete, :failed], _prefix: true
 
   MAX_DESCRIPTION_LENGTH = 1_500
 
@@ -55,6 +57,43 @@ class MediaAttachment < ApplicationRecord
     },
   }.freeze
 
+  VIDEO_FORMAT = {
+    format: 'mp4',
+    content_type: 'video/mp4',
+    convert_options: {
+      output: {
+        'loglevel' => 'fatal',
+        'movflags' => 'faststart',
+        'pix_fmt' => 'yuv420p',
+        'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'',
+        'vsync' => 'cfr',
+        'c:v' => 'h264',
+        'maxrate' => '1300K',
+        'bufsize' => '1300K',
+        'frames:v' => 60 * 60 * 3,
+        'crf' => 18,
+        'map_metadata' => '-1',
+      },
+    },
+  }.freeze
+
+  VIDEO_PASSTHROUGH_OPTIONS = {
+    video_codecs: ['h264'],
+    audio_codecs: ['aac', nil],
+    colorspaces: ['yuv420p'],
+    options: {
+      format: 'mp4',
+      convert_options: {
+        output: {
+          'loglevel' => 'fatal',
+          'map_metadata' => '-1',
+          'c:v' => 'copy',
+          'c:a' => 'copy',
+        },
+      },
+    },
+  }.freeze
+
   VIDEO_STYLES = {
     small: {
       convert_options: {
@@ -69,17 +108,7 @@ class MediaAttachment < ApplicationRecord
       blurhash: BLURHASH_OPTIONS,
     },
 
-    original: {
-      keep_same_format: true,
-      convert_options: {
-        output: {
-          'loglevel' => 'fatal',
-          'map_metadata' => '-1',
-          'c:v' => 'copy',
-          'c:a' => 'copy',
-        },
-      },
-    },
+    original: VIDEO_FORMAT.merge(passthrough_options: VIDEO_PASSTHROUGH_OPTIONS),
   }.freeze
 
   AUDIO_STYLES = {
@@ -96,26 +125,6 @@ class MediaAttachment < ApplicationRecord
     },
   }.freeze
 
-  VIDEO_FORMAT = {
-    format: 'mp4',
-    content_type: 'video/mp4',
-    convert_options: {
-      output: {
-        'loglevel' => 'fatal',
-        'movflags' => 'faststart',
-        'pix_fmt' => 'yuv420p',
-        'vf' => 'scale=\'trunc(iw/2)*2:trunc(ih/2)*2\'',
-        'vsync' => 'cfr',
-        'c:v' => 'h264',
-        'maxrate' => '1300K',
-        'bufsize' => '1300K',
-        'frames:v' => 60 * 60 * 3,
-        'crf' => 18,
-        'map_metadata' => '-1',
-      },
-    },
-  }.freeze
-
   VIDEO_CONVERTED_STYLES = {
     small: VIDEO_STYLES[:small],
     original: VIDEO_FORMAT,
@@ -124,6 +133,9 @@ class MediaAttachment < ApplicationRecord
   IMAGE_LIMIT = (ENV['MAX_IMAGE_SIZE'] || 10.megabytes).to_i
   VIDEO_LIMIT = (ENV['MAX_VIDEO_SIZE'] || 40.megabytes).to_i
 
+  MAX_VIDEO_MATRIX_LIMIT = 2_304_000 # 1920x1200px
+  MAX_VIDEO_FRAME_RATE   = 60
+
   belongs_to :account,          inverse_of: :media_attachments, optional: true
   belongs_to :status,           inverse_of: :media_attachments, optional: true
   belongs_to :scheduled_status, inverse_of: :media_attachments, optional: true
@@ -156,6 +168,10 @@ class MediaAttachment < ApplicationRecord
     remote_url.blank?
   end
 
+  def not_processed?
+    processing.present? && !processing_complete?
+  end
+
   def needs_redownload?
     file.blank? && remote_url.present?
   end
@@ -203,12 +219,21 @@ class MediaAttachment < ApplicationRecord
     "#{x},#{y}"
   end
 
+  attr_writer :delay_processing
+
+  def delay_processing?
+    @delay_processing
+  end
+
+  after_commit :enqueue_processing, on: :create
   after_commit :reset_parent_cache, on: :update
 
   before_create :prepare_description, unless: :local?
   before_create :set_shortcode
+  before_create :set_processing
 
   before_post_process :set_type_and_extension
+  before_post_process :check_video_dimensions
 
   before_save :set_meta
 
@@ -277,6 +302,21 @@ class MediaAttachment < ApplicationRecord
     end
   end
 
+  def set_processing
+    self.processing = delay_processing? ? :queued : :complete
+  end
+
+  def check_video_dimensions
+    return unless (video? || gifv?) && file.queued_for_write[:original].present?
+
+    movie = FFMPEG::Movie.new(file.queued_for_write[:original].path)
+
+    return unless movie.valid?
+
+    raise Mastodon::DimensionsValidationError, "#{movie.width}x#{movie.height} videos are not supported" if movie.width * movie.height > MAX_VIDEO_MATRIX_LIMIT
+    raise Mastodon::DimensionsValidationError, "#{movie.frame_rate.to_i}fps videos are not supported" if movie.frame_rate > MAX_VIDEO_FRAME_RATE
+  end
+
   def set_meta
     meta = populate_meta
 
@@ -322,9 +362,11 @@ class MediaAttachment < ApplicationRecord
     }.compact
   end
 
-  def reset_parent_cache
-    return if status_id.nil?
+  def enqueue_processing
+    PostProcessMediaWorker.perform_async(id) if delay_processing?
+  end
 
-    Rails.cache.delete("statuses/#{status_id}")
+  def reset_parent_cache
+    Rails.cache.delete("statuses/#{status_id}") if status_id.present?
   end
 end
diff --git a/app/models/report.rb b/app/models/report.rb
index fb2e040ee..356c23d68 100644
--- a/app/models/report.rb
+++ b/app/models/report.rb
@@ -59,6 +59,14 @@ class Report < ApplicationRecord
   end
 
   def resolve!(acting_account)
+    if account_id == -99 && target_account.trust_level == Account::TRUST_LEVELS[:untrusted]
+      # This is an automated report and it is being dismissed, so it's
+      # a false positive, in which case update the account's trust level
+      # to prevent further spam checks
+
+      target_account.update(trust_level: Account::TRUST_LEVELS[:trusted])
+    end
+
     RemovalWorker.push_bulk(Status.with_discarded.discarded.where(id: status_ids).pluck(:id)) { |status_id| [status_id, { immediate: true }] }
     update!(action_taken: true, action_taken_by_account_id: acting_account.id)
   end
diff --git a/app/models/status.rb b/app/models/status.rb
index b2d3c3f3b..a78717d0c 100644
--- a/app/models/status.rb
+++ b/app/models/status.rb
@@ -148,10 +148,12 @@ class Status < ApplicationRecord
       ids += mentions.where(account: Account.local).pluck(:account_id)
       ids += favourites.where(account: Account.local).pluck(:account_id)
       ids += reblogs.where(account: Account.local).pluck(:account_id)
+      ids += bookmarks.where(account: Account.local).pluck(:account_id)
     else
       ids += preloaded.mentions[id] || []
       ids += preloaded.favourites[id] || []
       ids += preloaded.reblogs[id] || []
+      ids += preloaded.bookmarks[id] || []
     end
 
     ids.uniq
diff --git a/app/serializers/rest/media_attachment_serializer.rb b/app/serializers/rest/media_attachment_serializer.rb
index 1b3498ea4..cc10e3001 100644
--- a/app/serializers/rest/media_attachment_serializer.rb
+++ b/app/serializers/rest/media_attachment_serializer.rb
@@ -12,7 +12,9 @@ class REST::MediaAttachmentSerializer < ActiveModel::Serializer
   end
 
   def url
-    if object.needs_redownload?
+    if object.not_processed?
+      nil
+    elsif object.needs_redownload?
       media_proxy_url(object.id, :original)
     else
       full_asset_url(object.file.url(:original))
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index d5ede0388..7b4c53d50 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -94,6 +94,7 @@ class ActivityPub::ProcessAccountService < BaseService
     @account.statuses_count    = outbox_total_items    if outbox_total_items.present?
     @account.following_count   = following_total_items if following_total_items.present?
     @account.followers_count   = followers_total_items if followers_total_items.present?
+    @account.hide_collections  = following_private? || followers_private?
     @account.moved_to_account  = @json['movedTo'].present? ? moved_account : nil
   end
 
@@ -166,26 +167,36 @@ class ActivityPub::ProcessAccountService < BaseService
   end
 
   def outbox_total_items
-    collection_total_items('outbox')
+    collection_info('outbox').first
   end
 
   def following_total_items
-    collection_total_items('following')
+    collection_info('following').first
   end
 
   def followers_total_items
-    collection_total_items('followers')
+    collection_info('followers').first
   end
 
-  def collection_total_items(type)
-    return if @json[type].blank?
+  def following_private?
+    !collection_info('following').last
+  end
+
+  def followers_private?
+    !collection_info('followers').last
+  end
+
+  def collection_info(type)
+    return [nil, nil] if @json[type].blank?
     return @collections[type] if @collections.key?(type)
 
     collection = fetch_resource_without_id_validation(@json[type])
 
-    @collections[type] = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil
+    total_items = collection.is_a?(Hash) && collection['totalItems'].present? && collection['totalItems'].is_a?(Numeric) ? collection['totalItems'] : nil
+    has_first_page = collection.is_a?(Hash) && collection['first'].present?
+    @collections[type] = [total_items, has_first_page]
   rescue HTTP::Error, OpenSSL::SSL::SSLError
-    @collections[type] = nil
+    @collections[type] = [nil, nil]
   end
 
   def moved_account
diff --git a/app/services/fetch_resource_service.rb b/app/services/fetch_resource_service.rb
index abe7766d4..880cdde92 100644
--- a/app/services/fetch_resource_service.rb
+++ b/app/services/fetch_resource_service.rb
@@ -5,6 +5,8 @@ class FetchResourceService < BaseService
 
   ACCEPT_HEADER = 'application/activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams", text/html;q=0.1'
 
+  attr_reader :response_code
+
   def call(url)
     return if url.blank?
 
@@ -27,6 +29,7 @@ class FetchResourceService < BaseService
   end
 
   def process_response(response, terminal = false)
+    @response_code = response.code
     return nil if response.code != 200
 
     if ['application/activity+json', 'application/ld+json'].include?(response.mime_type)
diff --git a/app/services/post_status_service.rb b/app/services/post_status_service.rb
index 5d3b8d725..5b181b193 100644
--- a/app/services/post_status_service.rb
+++ b/app/services/post_status_service.rb
@@ -110,6 +110,7 @@ class PostStatusService < BaseService
     @media = @account.media_attachments.where(status_id: nil).where(id: @options[:media_ids].take(4).map(&:to_i))
 
     raise Mastodon::ValidationError, I18n.t('media_attachments.validations.images_and_video') if @media.size > 1 && @media.find(&:audio_or_video?)
+    raise Mastodon::ValidationError, I18n.t('media_attachments.validations.not_ready') if @media.any?(&:not_processed?)
   end
 
   def language_from_option(str)
diff --git a/app/services/resolve_url_service.rb b/app/services/resolve_url_service.rb
index 1a2b0d60c..78080d878 100644
--- a/app/services/resolve_url_service.rb
+++ b/app/services/resolve_url_service.rb
@@ -12,7 +12,7 @@ class ResolveURLService < BaseService
       process_local_url
     elsif !fetched_resource.nil?
       process_url
-    elsif @on_behalf_of.present?
+    else
       process_url_from_db
     end
   end
@@ -30,6 +30,8 @@ class ResolveURLService < BaseService
   end
 
   def process_url_from_db
+    return unless @on_behalf_of.present? && [401, 403, 404].include?(fetch_resource_service.response_code)
+
     # It may happen that the resource is a private toot, and thus not fetchable,
     # but we can return the toot if we already know about it.
     status = Status.find_by(uri: @url) || Status.find_by(url: @url)
@@ -40,7 +42,11 @@ class ResolveURLService < BaseService
   end
 
   def fetched_resource
-    @fetched_resource ||= FetchResourceService.new.call(@url)
+    @fetched_resource ||= fetch_resource_service.call(@url)
+  end
+
+  def fetch_resource_service
+    @_fetch_resource_service ||= FetchResourceService.new
   end
 
   def resource_url
diff --git a/app/views/admin/account_actions/new.html.haml b/app/views/admin/account_actions/new.html.haml
index 20fbeef33..aa88b1448 100644
--- a/app/views/admin/account_actions/new.html.haml
+++ b/app/views/admin/account_actions/new.html.haml
@@ -21,7 +21,7 @@
 
     - unless @warning_presets.empty?
       .fields-group
-        = f.input :warning_preset_id, collection: @warning_presets, label_method: :text, wrapper: :with_block_label
+        = f.input :warning_preset_id, collection: @warning_presets, label_method: ->(warning_preset) { [warning_preset.title.presence, truncate(warning_preset.text)].compact.join(' - ') }, wrapper: :with_block_label
 
     .fields-group
       = f.input :text, as: :text, wrapper: :with_block_label, hint: t('simple_form.hints.admin_account_action.text_html', path: admin_warning_presets_path)
diff --git a/app/views/admin/accounts/show.html.haml b/app/views/admin/accounts/show.html.haml
index a30b78db2..744d17d1f 100644
--- a/app/views/admin/accounts/show.html.haml
+++ b/app/views/admin/accounts/show.html.haml
@@ -96,10 +96,17 @@
               = table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user)
 
           %tr
-            %th= t('admin.accounts.email')
-            %td= @account.user_email
+            %th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
+            %td{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= @account.user_email
             %td= table_link_to 'edit', t('admin.accounts.change_email.label'), admin_account_change_email_path(@account.id) if can?(:change_email, @account.user)
 
+          %tr
+            %td= table_link_to 'search', t('admin.accounts.search_same_email_domain'), admin_accounts_path(email: "%@#{@account.user_email.split('@').last}")
+
+          - if can?(:create, :email_domain_block)
+            %tr
+              %td= table_link_to 'ban', t('admin.accounts.add_email_domain_block'), new_admin_email_domain_block_path(_domain: @account.user_email.split('@').last)
+
           - if @account.user_unconfirmed_email.present?
             %tr
               %th= t('admin.accounts.unconfirmed_email')
@@ -204,7 +211,7 @@
         = link_to t('admin.accounts.perform_full_suspension'), new_admin_account_action_path(@account.id, type: 'suspend'), class: 'button button--destructive' if can?(:suspend, @account)
 
       - unless @account.local?
-        - if DomainBlock.where(domain: @account.domain).exists?
+        - if DomainBlock.rule_for(@account.domain)
           = link_to t('admin.domain_blocks.view'), admin_instance_path(@account.domain), class: 'button'
         - else
           = link_to t('admin.domain_blocks.add_new'), new_admin_domain_block_path(_domain: @account.domain), class: 'button button--destructive'
diff --git a/app/views/admin/email_domain_blocks/_email_domain_block.html.haml b/app/views/admin/email_domain_blocks/_email_domain_block.html.haml
index bf66c9001..41ab8c171 100644
--- a/app/views/admin/email_domain_blocks/_email_domain_block.html.haml
+++ b/app/views/admin/email_domain_blocks/_email_domain_block.html.haml
@@ -3,3 +3,13 @@
     %samp= email_domain_block.domain
   %td
     = table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(email_domain_block), method: :delete
+
+- email_domain_block.children.each do |child_email_domain_block|
+  %tr
+    %td
+      %samp= child_email_domain_block.domain
+      %span.muted-hint
+        = surround '(', ')' do
+          = t('admin.email_domain_blocks.from_html', domain: content_tag(:samp, email_domain_block.domain))
+    %td
+      = table_link_to 'trash', t('admin.email_domain_blocks.delete'), admin_email_domain_block_path(child_email_domain_block), method: :delete
diff --git a/app/views/admin/email_domain_blocks/new.html.haml b/app/views/admin/email_domain_blocks/new.html.haml
index f372fa512..4a346f240 100644
--- a/app/views/admin/email_domain_blocks/new.html.haml
+++ b/app/views/admin/email_domain_blocks/new.html.haml
@@ -5,7 +5,10 @@
   = render 'shared/error_messages', object: @email_domain_block
 
   .fields-group
-    = f.input :domain, wrapper: :with_label, label: t('admin.email_domain_blocks.domain')
+    = f.input :domain, wrapper: :with_block_label, label: t('admin.email_domain_blocks.domain')
+
+  .fields-group
+    = f.input :with_dns_records, as: :boolean, wrapper: :with_label
 
   .actions
     = f.button :button, t('.create'), type: :submit
diff --git a/app/views/admin/warning_presets/_warning_preset.html.haml b/app/views/admin/warning_presets/_warning_preset.html.haml
new file mode 100644
index 000000000..a58199c80
--- /dev/null
+++ b/app/views/admin/warning_presets/_warning_preset.html.haml
@@ -0,0 +1,10 @@
+.announcements-list__item
+  = link_to edit_admin_warning_preset_path(warning_preset), class: 'announcements-list__item__title' do
+    = warning_preset.title.presence || truncate(warning_preset.text)
+
+  .announcements-list__item__action-bar
+    .announcements-list__item__meta
+      = truncate(warning_preset.text)
+
+    %div
+      = table_link_to 'trash', t('admin.warning_presets.delete'), admin_warning_preset_path(warning_preset), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:destroy, warning_preset)
diff --git a/app/views/admin/warning_presets/edit.html.haml b/app/views/admin/warning_presets/edit.html.haml
index 9522746cd..b5c5107ef 100644
--- a/app/views/admin/warning_presets/edit.html.haml
+++ b/app/views/admin/warning_presets/edit.html.haml
@@ -5,6 +5,9 @@
   = render 'shared/error_messages', object: @warning_preset
 
   .fields-group
+    = f.input :title, wrapper: :with_block_label
+
+  .fields-group
     = f.input :text, wrapper: :with_block_label
 
   .actions
diff --git a/app/views/admin/warning_presets/index.html.haml b/app/views/admin/warning_presets/index.html.haml
index 45913ef73..dbc23fa30 100644
--- a/app/views/admin/warning_presets/index.html.haml
+++ b/app/views/admin/warning_presets/index.html.haml
@@ -6,6 +6,9 @@
     = render 'shared/error_messages', object: @warning_preset
 
     .fields-group
+      = f.input :title, wrapper: :with_block_label
+
+    .fields-group
       = f.input :text, wrapper: :with_block_label
 
     .actions
@@ -13,18 +16,9 @@
 
   %hr.spacer/
 
-- unless @warning_presets.empty?
-  .table-wrapper
-    %table.table
-      %thead
-        %tr
-          %th= t('simple_form.labels.account_warning_preset.text')
-          %th
-      %tbody
-        - @warning_presets.each do |preset|
-          %tr
-            %td
-              = Formatter.instance.linkify(preset.text)
-            %td
-              = table_link_to 'pencil', t('admin.warning_presets.edit'), edit_admin_warning_preset_path(preset)
-              = table_link_to 'trash', t('admin.warning_presets.delete'), admin_warning_preset_path(preset), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }
+- if @warning_presets.empty?
+  %div.muted-hint.center-text
+    = t 'admin.warning_presets.empty'
+- else
+  .announcements-list
+    = render partial: 'warning_preset', collection: @warning_presets
diff --git a/app/workers/backup_worker.rb b/app/workers/backup_worker.rb
index e4c609d70..7b0b52844 100644
--- a/app/workers/backup_worker.rb
+++ b/app/workers/backup_worker.rb
@@ -9,8 +9,12 @@ class BackupWorker
     backup_id = msg['args'].first
 
     ActiveRecord::Base.connection_pool.with_connection do
-      backup = Backup.find(backup_id)
-      backup&.destroy
+      begin
+        backup = Backup.find(backup_id)
+        backup.destroy
+      rescue ActiveRecord::RecordNotFound
+        true
+      end
     end
   end
 
diff --git a/app/workers/post_process_media_worker.rb b/app/workers/post_process_media_worker.rb
new file mode 100644
index 000000000..d3ebda194
--- /dev/null
+++ b/app/workers/post_process_media_worker.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+class PostProcessMediaWorker
+  include Sidekiq::Worker
+
+  sidekiq_options retry: 1, dead: false
+
+  sidekiq_retries_exhausted do |msg|
+    media_attachment_id = msg['args'].first
+
+    ActiveRecord::Base.connection_pool.with_connection do
+      begin
+        media_attachment = MediaAttachment.find(media_attachment_id)
+        media_attachment.processing = :failed
+        media_attachment.save
+      rescue ActiveRecord::RecordNotFound
+        true
+      end
+    end
+
+    Sidekiq.logger.error("Processing media attachment #{media_attachment_id} failed with #{msg['error_message']}")
+  end
+
+  def perform(media_attachment_id)
+    media_attachment = MediaAttachment.find(media_attachment_id)
+    media_attachment.processing = :in_progress
+    media_attachment.save
+    media_attachment.file.reprocess_original!
+    media_attachment.processing = :complete
+    media_attachment.save
+  rescue ActiveRecord::RecordNotFound
+    true
+  end
+end
diff --git a/config/application.rb b/config/application.rb
index 1baa166ce..cd599eefc 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -7,6 +7,7 @@ require 'rails/all'
 Bundler.require(*Rails.groups)
 
 require_relative '../app/lib/exceptions'
+require_relative '../lib/paperclip/attachment_extensions'
 require_relative '../lib/paperclip/lazy_thumbnail'
 require_relative '../lib/paperclip/gif_transcoder'
 require_relative '../lib/paperclip/video_transcoder'
diff --git a/config/deploy.rb b/config/deploy.rb
index 4dc36c65c..79550baed 100644
--- a/config/deploy.rb
+++ b/config/deploy.rb
@@ -1,6 +1,6 @@
 # frozen_string_literal: true
 
-lock '3.11.2'
+lock '3.12.1'
 
 set :repo_url, ENV.fetch('REPO', 'https://github.com/tootsuite/mastodon.git')
 set :branch, ENV.fetch('BRANCH', 'master')
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index 7f8a40d7b..288453a04 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -19,4 +19,4 @@ Sidekiq.configure_client do |config|
   config.redis = redis_params
 end
 
-Sidekiq::Logging.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
+Sidekiq.logger.level = ::Logger.const_get(ENV.fetch('RAILS_LOG_LEVEL', 'info').upcase.to_s)
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index f5a6f067d..5c73967d6 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -562,7 +562,6 @@ ar:
     warning_presets:
       add_new: إضافة واحد جديد
       delete: حذف
-      edit: تعديل
       edit_preset: تعديل نموذج التحذير
       title: إدارة نماذج التحذير
   admin_mailer:
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index 1c30b6b7a..22782ae16 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -573,7 +573,6 @@ ca:
     warning_presets:
       add_new: Afegeix-ne un de nou
       delete: Esborra
-      edit: Edita
       edit_preset: Edita l'avís predeterminat
       title: Gestiona les configuracions predefinides dels avisos
   admin_mailer:
diff --git a/config/locales/co.yml b/config/locales/co.yml
index 24f7f45fc..d9127a385 100644
--- a/config/locales/co.yml
+++ b/config/locales/co.yml
@@ -573,7 +573,6 @@ co:
     warning_presets:
       add_new: Aghjunghje
       delete: Sguassà
-      edit: Cambià
       edit_preset: Cambià a preselezzione d'avertimentu
       title: Amministrà e preselezzione d'avertimentu
   admin_mailer:
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index bab669e7e..23161ec5c 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -588,7 +588,6 @@ cs:
     warning_presets:
       add_new: Přidat nové
       delete: Smazat
-      edit: Upravit
       edit_preset: Upravit předlohu pro varování
       title: Spravovat předlohy pro varování
   admin_mailer:
diff --git a/config/locales/cy.yml b/config/locales/cy.yml
index afca0212a..a9e8a26da 100644
--- a/config/locales/cy.yml
+++ b/config/locales/cy.yml
@@ -605,7 +605,6 @@ cy:
     warning_presets:
       add_new: Ychwanegu newydd
       delete: Dileu
-      edit: Golygu
       edit_preset: Golygu rhagosodiad rhybudd
       title: Rheoli rhagosodiadau rhybudd
   admin_mailer:
diff --git a/config/locales/da.yml b/config/locales/da.yml
index 1cdf7722e..c978029b3 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -489,7 +489,6 @@ da:
       most_recent: Seneste
     warning_presets:
       delete: Slet
-      edit: Rediger
   admin_mailer:
     new_report:
       body: "%{reporter} har anmeldt %{target}"
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 50f994473..6907efc60 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -573,7 +573,6 @@ de:
     warning_presets:
       add_new: Neu hinzufügen
       delete: Löschen
-      edit: Bearbeiten
       edit_preset: Warnungsvorlage bearbeiten
       title: Warnungsvorlagen verwalten
   admin_mailer:
diff --git a/config/locales/el.yml b/config/locales/el.yml
index 85c7bc648..dd9c93172 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -573,7 +573,6 @@ el:
     warning_presets:
       add_new: Πρόσθεση νέου
       delete: Διαγραφή
-      edit: Ενημέρωση
       edit_preset: Ενημέρωση προκαθορισμένης προειδοποίησης
       title: Διαχείριση προκαθορισμένων προειδοποιήσεων
   admin_mailer:
diff --git a/config/locales/en.yml b/config/locales/en.yml
index a1dc1c326..f07a554f1 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -92,6 +92,7 @@ en:
       delete: Delete
       destroyed_msg: Moderation note successfully destroyed!
     accounts:
+      add_email_domain_block: Blacklist e-mail domain
       approve: Approve
       approve_all: Approve all
       are_you_sure: Are you sure?
@@ -172,6 +173,7 @@ en:
         staff: Staff
         user: User
       search: Search
+      search_same_email_domain: Other users with the same e-mail domain
       search_same_ip: Other users with the same IP
       shared_inbox_url: Shared inbox URL
       show:
@@ -359,6 +361,7 @@ en:
       destroyed_msg: Successfully deleted e-mail domain from blacklist
       domain: Domain
       empty: No e-mail domains currently blacklisted.
+      from_html: from %{domain}
       new:
         create: Add domain
         title: New e-mail blacklist entry
@@ -589,7 +592,6 @@ en:
     warning_presets:
       add_new: Add new
       delete: Delete
-      edit: Edit
       edit_preset: Edit warning preset
       title: Manage warning presets
   admin_mailer:
@@ -867,6 +869,7 @@ en:
   media_attachments:
     validations:
       images_and_video: Cannot attach a video to a status that already contains images
+      not_ready: Cannot attach files that have not finished processing. Try again in a moment!
       too_many: Cannot attach more than 4 files
   migrations:
     acct: Moved to
diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml
index 0742559ed..1375ebb33 100644
--- a/config/locales/en_GB.yml
+++ b/config/locales/en_GB.yml
@@ -474,7 +474,6 @@ en_GB:
     warning_presets:
       add_new: Add new
       delete: Delete
-      edit: Edit
       edit_preset: Edit warning preset
       title: Manage warning presets
   admin_mailer:
diff --git a/config/locales/eo.yml b/config/locales/eo.yml
index b3cb2b523..32771b4c4 100644
--- a/config/locales/eo.yml
+++ b/config/locales/eo.yml
@@ -557,7 +557,6 @@ eo:
     warning_presets:
       add_new: Aldoni novan
       delete: Forigi
-      edit: Redakti
       edit_preset: Redakti avertan antaŭagordon
       title: Administri avertajn antaŭagordojn
   admin_mailer:
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
index 6eec00cb6..67fb83de2 100644
--- a/config/locales/es-AR.yml
+++ b/config/locales/es-AR.yml
@@ -573,7 +573,6 @@ es-AR:
     warning_presets:
       add_new: Agregar nuevo
       delete: Eliminar
-      edit: Editar
       edit_preset: Editar preajuste de advertencia
       title: Administrar preajustes de advertencia
   admin_mailer:
diff --git a/config/locales/es.yml b/config/locales/es.yml
index a26143018..3acf29b15 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -573,7 +573,6 @@ es:
     warning_presets:
       add_new: Añadir nuevo
       delete: Borrar
-      edit: Editar
       edit_preset: Editar aviso predeterminado
       title: Editar configuración predeterminada de avisos
   admin_mailer:
diff --git a/config/locales/et.yml b/config/locales/et.yml
index 716da9010..8e3d56622 100644
--- a/config/locales/et.yml
+++ b/config/locales/et.yml
@@ -576,7 +576,6 @@ et:
     warning_presets:
       add_new: Lisa uus
       delete: Kustuta
-      edit: Redigeeri
       edit_preset: Redigeeri hoiatuse eelseadistust
       title: Halda hoiatuste eelseadistusi
   admin_mailer:
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 3ca68d321..e44fc61b0 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -573,7 +573,6 @@ eu:
     warning_presets:
       add_new: Gehitu berria
       delete: Ezabatu
-      edit: Editatu
       edit_preset: Editatu abisu aurre-ezarpena
       title: Kudeatu abisu aurre-ezarpenak
   admin_mailer:
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 02bbd2938..aca4df69b 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -575,7 +575,6 @@ fa:
     warning_presets:
       add_new: افزودن تازه
       delete: زدودن
-      edit: ویرایش
       edit_preset: ویرایش هشدار پیش‌فرض
       title: مدیریت هشدارهای پیش‌فرض
   admin_mailer:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index bf79bc0ff..c1d8cc2bf 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -573,7 +573,6 @@ fr:
     warning_presets:
       add_new: Ajouter un nouveau
       delete: Effacer
-      edit: Éditer
       edit_preset: Éditer les avertissements prédéfinis
       title: Gérer les avertissements prédéfinis
   admin_mailer:
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index c3a33932d..9f0f16b5b 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -573,7 +573,6 @@ gl:
     warning_presets:
       add_new: Engadir novo
       delete: Eliminar
-      edit: Editar
       edit_preset: Editar aviso preestablecido
       title: Xestionar avisos preestablecidos
   admin_mailer:
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 2d7f3a137..c6b619dd2 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -575,7 +575,6 @@ hu:
     warning_presets:
       add_new: Új hozzáadása
       delete: Törlés
-      edit: Szerkesztés
       edit_preset: Figyelmeztetés szerkesztése
       title: Figyelmeztetések
   admin_mailer:
diff --git a/config/locales/id.yml b/config/locales/id.yml
index ca222946c..bfa71184f 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -565,7 +565,6 @@ id:
     warning_presets:
       add_new: Tambah baru
       delete: Hapus
-      edit: Sunting
       edit_preset: Sunting preset peringatan
       title: Kelola preset peringatan
   admin_mailer:
diff --git a/config/locales/is.yml b/config/locales/is.yml
index d6cf23966..336533d52 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -573,7 +573,6 @@ is:
     warning_presets:
       add_new: Bæta við nýju
       delete: Eyða
-      edit: Breyta
       edit_preset: Breyta forstilltri aðvörun
       title: Sýsla með forstilltar aðvaranir
   admin_mailer:
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 2ccdc076c..636ae8924 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -573,7 +573,6 @@ it:
     warning_presets:
       add_new: Aggiungi nuovo
       delete: Cancella
-      edit: Modifica
       edit_preset: Modifica avviso predefinito
       title: Gestisci avvisi predefiniti
   admin_mailer:
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 00e76a8da..130ad250d 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -565,7 +565,6 @@ ja:
     warning_presets:
       add_new: 追加
       delete: 削除
-      edit: 編集
       edit_preset: プリセット警告文を編集
       title: プリセット警告文を管理
   admin_mailer:
diff --git a/config/locales/kab.yml b/config/locales/kab.yml
index 03f4d8c13..b398bebd9 100644
--- a/config/locales/kab.yml
+++ b/config/locales/kab.yml
@@ -330,7 +330,6 @@ kab:
     warning_presets:
       add_new: Rnu amaynut
       delete: Kkes
-      edit: Ẓreg
   admin_mailer:
     new_report:
       subject: Aneqqis amaynut i %{instance} (#%{id})
diff --git a/config/locales/kk.yml b/config/locales/kk.yml
index 416a5fc7d..bb7a57e87 100644
--- a/config/locales/kk.yml
+++ b/config/locales/kk.yml
@@ -555,7 +555,6 @@ kk:
     warning_presets:
       add_new: Add nеw
       delete: Deletе
-      edit: Еdit
       edit_preset: Edit warning prеset
       title: Manage warning presеts
   admin_mailer:
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index e70fbef21..6ca0b2acc 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -567,7 +567,6 @@ ko:
     warning_presets:
       add_new: 새로 추가
       delete: 삭제
-      edit: 편집
       edit_preset: 경고 틀 수정
       title: 경고 틀 관리
   admin_mailer:
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 9af094c01..5a4542ea8 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -410,7 +410,6 @@ lt:
     warning_presets:
       add_new: Pridėti naują
       delete: Ištrinti
-      edit: Keisti
       edit_preset: Keisti įspėjimo nustatymus
       title: Valdyti įspėjimo nustatymus
   admin_mailer:
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 976072368..f688d5dbd 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -573,7 +573,6 @@ nl:
     warning_presets:
       add_new: Nieuwe toevoegen
       delete: Verwijderen
-      edit: Bewerken
       edit_preset: Voorinstelling van waarschuwing bewerken
       title: Voorinstellingen van waarschuwingen beheren
   admin_mailer:
diff --git a/config/locales/nn.yml b/config/locales/nn.yml
index fd61f2156..07b6397c6 100644
--- a/config/locales/nn.yml
+++ b/config/locales/nn.yml
@@ -566,7 +566,6 @@ nn:
     warning_presets:
       add_new: Legg til ny
       delete: Slett
-      edit: Rediger
       edit_preset: Endr åtvaringsoppsett
       title: Handsam åtvaringsoppsett
   admin_mailer:
diff --git a/config/locales/no.yml b/config/locales/no.yml
index 256ed99a3..4a1b859dc 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -561,7 +561,6 @@
     warning_presets:
       add_new: Legg til ny
       delete: Slett
-      edit: Rediger
   admin_mailer:
     new_pending_account:
       body: Detaljer om den nye kontoen er nedenfor. Du kan godkjenne eller avvise denne søknaden.
diff --git a/config/locales/oc.yml b/config/locales/oc.yml
index 4a60227ab..d3f3a1007 100644
--- a/config/locales/oc.yml
+++ b/config/locales/oc.yml
@@ -558,7 +558,6 @@ oc:
     warning_presets:
       add_new: N’ajustar un nòu
       delete: Escafar
-      edit: Modificar
       edit_preset: Modificar lo tèxt predefinit d’avertiment
       title: Gerir los tèxtes predefinits
   admin_mailer:
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 6f04720c5..4281153f0 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -541,7 +541,6 @@ pl:
     warning_presets:
       add_new: Dodaj nowy
       delete: Usuń
-      edit: Edytuj
       edit_preset: Edytuj szablon ostrzeżenia
       title: Zarządzaj szablonami ostrzeżeń
   admin_mailer:
diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml
index abea40130..419ea5a73 100644
--- a/config/locales/pt-BR.yml
+++ b/config/locales/pt-BR.yml
@@ -573,7 +573,6 @@ pt-BR:
     warning_presets:
       add_new: Adicionar novo
       delete: Excluir
-      edit: Editar
       edit_preset: Editar o aviso pré-definido
       title: Gerenciar os avisos pré-definidos
   admin_mailer:
diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml
index 477c9d3a3..9d3a503b1 100644
--- a/config/locales/pt-PT.yml
+++ b/config/locales/pt-PT.yml
@@ -573,7 +573,6 @@ pt-PT:
     warning_presets:
       add_new: Adicionar novo
       delete: Apagar
-      edit: Editar
       edit_preset: Editar o aviso predefinido
       title: Gerir os avisos predefinidos
   admin_mailer:
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 6196ac3eb..f1547ddf2 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -594,7 +594,6 @@ ru:
     warning_presets:
       add_new: Добавить
       delete: Удалить
-      edit: Изменить
       edit_preset: Удалить шаблон предупреждения
       title: Управление шаблонами предупреждений
   admin_mailer:
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index cf8f7120d..141ef574b 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -8,6 +8,7 @@ en:
         acct: Specify the username@domain of the account you want to move to
       account_warning_preset:
         text: You can use toot syntax, such as URLs, hashtags and mentions
+        title: Optional. Not visible to the recipient
       admin_account_action:
         include_statuses: The user will see which toots have caused the moderation action or warning
         send_email_notification: The user will receive an explanation of what happened with their account
@@ -58,6 +59,9 @@ en:
         whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
       domain_allow:
         domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored
+      email_domain_block:
+        domain: This can be the domain name that shows up in the e-mail address, the MX record that domain resolves to, or IP of the server that MX record resolves to. Those will be checked upon user sign-up and the sign-up will be rejected.
+        with_dns_records: An attempt to resolve the given domain's DNS records will be made and the results will also be blacklisted
       featured_tag:
         name: 'You might want to use one of these:'
       form_challenge:
@@ -83,6 +87,7 @@ en:
         acct: Handle of the new account
       account_warning_preset:
         text: Preset text
+        title: Title
       admin_account_action:
         include_statuses: Include reported toots in the e-mail
         send_email_notification: Notify the user per e-mail
@@ -163,6 +168,8 @@ en:
         username: Username
         username_or_email: Username or Email
         whole_word: Whole word
+      email_domain_block:
+        with_dns_records: Include MX records and IPs of the domain
       featured_tag:
         name: Hashtag
       interactions:
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index dbee6bb12..2986f83d8 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -574,7 +574,6 @@ sk:
     warning_presets:
       add_new: Pridaj nové
       delete: Vymaž
-      edit: Uprav
       edit_preset: Uprav varovnú predlohu
       title: Spravuj varovné predlohy
   admin_mailer:
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index afb928f11..91720c602 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -485,7 +485,6 @@ sl:
     warning_presets:
       add_new: Dodaj novo
       delete: Izbriši
-      edit: Uredi
       edit_preset: Uredi prednastavitev opozoril
       title: Upravljaj prednastavitev opozoril
   admin_mailer:
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 6a7a945c4..0e20902ff 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -415,7 +415,6 @@ sq:
     warning_presets:
       add_new: Shtoni të ri
       delete: Fshije
-      edit: Përpunoni
       edit_preset: Përpunoni sinjalizim të paracaktuar
       title: Administroni sinjalizime të paracaktuara
   admin_mailer:
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index c68681215..d7fb6f74d 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -431,7 +431,6 @@ sr:
     warning_presets:
       add_new: Додај нови
       delete: Избриши
-      edit: Уреди
       edit_preset: Уреди пресет упозорења
       title: Управљај пресетима упозорења
   admin_mailer:
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index 0094ff06b..4b67ff19c 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -448,7 +448,6 @@ sv:
     warning_presets:
       add_new: Lägg till ny
       delete: Radera
-      edit: Redigera
   admin_mailer:
     new_report:
       body: "%{reporter} har rapporterat %{target}"
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 7d6ec0b13..53267c805 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -488,7 +488,6 @@ th:
     warning_presets:
       add_new: เพิ่มใหม่
       delete: ลบ
-      edit: แก้ไข
       edit_preset: แก้ไขคำเตือนที่ตั้งไว้ล่วงหน้า
       title: จัดการคำเตือนที่ตั้งไว้ล่วงหน้า
   admin_mailer:
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index cde7f1c83..1dcf9ccea 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -573,7 +573,6 @@ tr:
     warning_presets:
       add_new: Yeni ekle
       delete: Sil
-      edit: Düzenle
       edit_preset: Uyarı ön-ayarını düzenle
       title: Uyarı ön-ayarlarını yönet
   admin_mailer:
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 967a02717..3df83e756 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -591,7 +591,6 @@ uk:
     warning_presets:
       add_new: Додати новий
       delete: Видалити
-      edit: Редагувати
       edit_preset: Редагувати шаблон попередження
       title: Управління шаблонами попереджень
   admin_mailer:
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index ec8e853fe..cba773417 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -534,7 +534,6 @@ vi:
     warning_presets:
       add_new: Thêm mới
       delete: Xóa bỏ
-      edit: Biên tập
       edit_preset: Chỉnh sửa cảnh báo đặt trước
       title: Quản lý cài đặt trước cảnh báo
   admin_mailer:
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index d6618dbbe..54230fb2f 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -565,7 +565,6 @@ zh-CN:
     warning_presets:
       add_new: 添加新条目
       delete: 删除
-      edit: 编辑
       edit_preset: 编辑预置警告
       title: 管理预设警告
   admin_mailer:
diff --git a/config/locales/zh-HK.yml b/config/locales/zh-HK.yml
index ffd5ba5e9..fd988e443 100644
--- a/config/locales/zh-HK.yml
+++ b/config/locales/zh-HK.yml
@@ -409,7 +409,6 @@ zh-HK:
     warning_presets:
       add_new: 新增
       delete: 刪除
-      edit: 編輯
   admin_mailer:
     new_report:
       body: "%{reporter} 舉報了用戶 %{target}"
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 5b25688ed..984bbcf13 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -408,7 +408,6 @@ zh-TW:
     warning_presets:
       add_new: 新增
       delete: 刪除
-      edit: 編輯
   admin_mailer:
     new_report:
       body: "%{reporter} 檢舉了使用者 %{target}"
diff --git a/config/routes.rb b/config/routes.rb
index 103abc6c1..7530c5b1f 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -346,7 +346,7 @@ Rails.application.routes.draw do
         end
       end
 
-      resources :media,        only: [:create, :update]
+      resources :media,        only: [:create, :update, :show]
       resources :blocks,       only: [:index]
       resources :mutes,        only: [:index] do
         collection do
@@ -463,6 +463,7 @@ Rails.application.routes.draw do
     end
 
     namespace :v2 do
+      resources :media, only: [:create]
       get '/search', to: 'search#index', as: :search
     end
 
diff --git a/db/migrate/20191212163405_add_hide_collections_to_accounts.rb b/db/migrate/20191212163405_add_hide_collections_to_accounts.rb
new file mode 100644
index 000000000..fa99b32e5
--- /dev/null
+++ b/db/migrate/20191212163405_add_hide_collections_to_accounts.rb
@@ -0,0 +1,5 @@
+class AddHideCollectionsToAccounts < ActiveRecord::Migration[5.2]
+  def change
+    add_column :accounts, :hide_collections, :boolean
+  end
+end
diff --git a/db/migrate/20200306035625_add_processing_to_media_attachments.rb b/db/migrate/20200306035625_add_processing_to_media_attachments.rb
new file mode 100644
index 000000000..131ffa52a
--- /dev/null
+++ b/db/migrate/20200306035625_add_processing_to_media_attachments.rb
@@ -0,0 +1,5 @@
+class AddProcessingToMediaAttachments < ActiveRecord::Migration[5.2]
+  def change
+    add_column :media_attachments, :processing, :integer
+  end
+end
diff --git a/db/migrate/20200312144258_add_title_to_account_warning_presets.rb b/db/migrate/20200312144258_add_title_to_account_warning_presets.rb
new file mode 100644
index 000000000..46a5350e7
--- /dev/null
+++ b/db/migrate/20200312144258_add_title_to_account_warning_presets.rb
@@ -0,0 +1,15 @@
+require Rails.root.join('lib', 'mastodon', 'migration_helpers')
+
+class AddTitleToAccountWarningPresets < ActiveRecord::Migration[5.2]
+  include Mastodon::MigrationHelpers
+
+  disable_ddl_transaction!
+
+  def up
+    safety_assured { add_column_with_default :account_warning_presets, :title, :string, default: '', allow_null: false }
+  end
+
+  def down
+    remove_column :account_warning_presets, :title
+  end
+end
diff --git a/db/migrate/20200312185443_add_parent_id_to_email_domain_blocks.rb b/db/migrate/20200312185443_add_parent_id_to_email_domain_blocks.rb
new file mode 100644
index 000000000..03915040c
--- /dev/null
+++ b/db/migrate/20200312185443_add_parent_id_to_email_domain_blocks.rb
@@ -0,0 +1,5 @@
+class AddParentIdToEmailDomainBlocks < ActiveRecord::Migration[5.2]
+  def change
+    add_reference :email_domain_blocks, :parent, null: true, default: nil, foreign_key: { on_delete: :cascade, to_table: :email_domain_blocks }, index: false
+  end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 73ac78b80..392cc739c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2020_01_26_203551) do
+ActiveRecord::Schema.define(version: 2020_03_12_185443) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -114,6 +114,7 @@ ActiveRecord::Schema.define(version: 2020_01_26_203551) do
     t.text "text", default: "", null: false
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
+    t.string "title", default: "", null: false
   end
 
   create_table "account_warnings", force: :cascade do |t|
@@ -170,6 +171,7 @@ ActiveRecord::Schema.define(version: 2020_01_26_203551) do
     t.datetime "silenced_at"
     t.datetime "suspended_at"
     t.integer "trust_level"
+    t.boolean "hide_collections"
     t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin
     t.index "lower((username)::text), lower((domain)::text)", name: "index_accounts_on_username_and_domain_lower", unique: true
     t.index ["moved_to_account_id"], name: "index_accounts_on_moved_to_account_id"
@@ -334,6 +336,7 @@ ActiveRecord::Schema.define(version: 2020_01_26_203551) do
     t.string "domain", default: "", null: false
     t.datetime "created_at", null: false
     t.datetime "updated_at", null: false
+    t.bigint "parent_id"
     t.index ["domain"], name: "index_email_domain_blocks_on_domain", unique: true
   end
 
@@ -460,6 +463,7 @@ ActiveRecord::Schema.define(version: 2020_01_26_203551) do
     t.text "description"
     t.bigint "scheduled_status_id"
     t.string "blurhash"
+    t.integer "processing"
     t.index ["account_id"], name: "index_media_attachments_on_account_id"
     t.index ["scheduled_status_id"], name: "index_media_attachments_on_scheduled_status_id"
     t.index ["shortcode"], name: "index_media_attachments_on_shortcode", unique: true
@@ -869,6 +873,7 @@ ActiveRecord::Schema.define(version: 2020_01_26_203551) do
   add_foreign_key "conversation_mutes", "accounts", name: "fk_225b4212bb", on_delete: :cascade
   add_foreign_key "conversation_mutes", "conversations", on_delete: :cascade
   add_foreign_key "custom_filters", "accounts", on_delete: :cascade
+  add_foreign_key "email_domain_blocks", "email_domain_blocks", column: "parent_id", on_delete: :cascade
   add_foreign_key "favourites", "accounts", name: "fk_5eb6c2b873", on_delete: :cascade
   add_foreign_key "favourites", "statuses", name: "fk_b0e856845e", on_delete: :cascade
   add_foreign_key "featured_tags", "accounts", on_delete: :cascade
diff --git a/lib/paperclip/attachment_extensions.rb b/lib/paperclip/attachment_extensions.rb
new file mode 100644
index 000000000..3b308af5f
--- /dev/null
+++ b/lib/paperclip/attachment_extensions.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+module Paperclip
+  module AttachmentExtensions
+    # We overwrite this method to support delayed processing in
+    # Sidekiq. Since we process the original file to reduce disk
+    # usage, and we still want to generate thumbnails straight
+    # away, it's the only style we need to exclude
+    def process_style?(style_name, style_args)
+      if style_name == :original && instance.respond_to?(:delay_processing?) && instance.delay_processing?
+        false
+      else
+        style_args.empty? || style_args.include?(style_name)
+      end
+    end
+
+    def reprocess_original!
+      old_original_path = path(:original)
+      reprocess!(:original)
+      new_original_path = path(:original)
+
+      if new_original_path != old_original_path
+        @queued_for_delete << old_original_path
+        flush_deletes
+      end
+    end
+  end
+end
+
+Paperclip::Attachment.prepend(Paperclip::AttachmentExtensions)
diff --git a/lib/paperclip/video_transcoder.rb b/lib/paperclip/video_transcoder.rb
index 66f7feda5..4d9544231 100644
--- a/lib/paperclip/video_transcoder.rb
+++ b/lib/paperclip/video_transcoder.rb
@@ -5,12 +5,22 @@ module Paperclip
   # to check when uploaded videos are actually gifv's
   class VideoTranscoder < Paperclip::Processor
     def make
-      meta = ::Av.cli.identify(@file.path)
+      movie = FFMPEG::Movie.new(@file.path)
 
-      attachment.instance.type = MediaAttachment.types[:gifv] unless meta[:audio_encode]
-      options[:format] = File.extname(attachment.instance.file_file_name)[1..-1] if options[:keep_same_format]
+      attachment.instance.type = MediaAttachment.types[:gifv] unless movie.audio_codec
 
-      Paperclip::Transcoder.make(file, options, attachment)
+      Paperclip::Transcoder.make(file, actual_options(movie), attachment)
+    end
+
+    private
+
+    def actual_options(movie)
+      opts = options[:passthrough_options]
+      if opts && opts[:video_codecs].include?(movie.video_codec) && opts[:audio_codecs].include?(movie.audio_codec) && opts[:colorspaces].include?(movie.colorspace)
+        opts[:options]
+      else
+        options
+      end
     end
   end
 end
diff --git a/package.json b/package.json
index 9e221eefa..be4eb877f 100644
--- a/package.json
+++ b/package.json
@@ -85,7 +85,7 @@
     "classnames": "^2.2.5",
     "compression-webpack-plugin": "^3.1.0",
     "copy-webpack-plugin": "^5.1.1",
-    "cross-env": "^6.0.3",
+    "cross-env": "^7.0.2",
     "css-loader": "^3.4.2",
     "cssnano": "^4.1.10",
     "detect-passive-events": "^1.0.2",
@@ -96,7 +96,7 @@
     "exif-js": "^2.3.0",
     "express": "^4.17.1",
     "favico.js": "^0.3.10",
-    "file-loader": "^5.0.2",
+    "file-loader": "^5.1.0",
     "font-awesome": "^4.7.0",
     "glob": "^7.1.6",
     "history": "^4.10.1",
@@ -113,7 +113,7 @@
     "mark-loader": "^0.1.6",
     "marky": "^1.2.1",
     "mini-css-extract-plugin": "^0.9.0",
-    "mkdirp": "^0.5.1",
+    "mkdirp": "^1.0.3",
     "npmlog": "^4.1.2",
     "object-assign": "^4.1.1",
     "object-fit-images": "^3.2.3",
@@ -126,11 +126,11 @@
     "promise.prototype.finally": "^3.1.2",
     "prop-types": "^15.5.10",
     "punycode": "^2.1.0",
-    "rails-ujs": "^5.2.4",
+    "@rails/ujs": "^6.0.2",
     "react": "^16.12.0",
-    "react-dom": "^16.12.0",
+    "react-dom": "^16.13.0",
     "react-hotkeys": "^1.1.4",
-    "react-immutable-proptypes": "^2.1.0",
+    "react-immutable-proptypes": "^2.2.0",
     "react-immutable-pure-component": "^1.1.1",
     "react-intl": "^2.9.0",
     "react-masonry-infinite": "^1.2.2",
@@ -146,7 +146,7 @@
     "react-swipeable-views": "^0.13.9",
     "react-textarea-autosize": "^7.1.2",
     "react-toggle": "^4.1.1",
-    "redis": "^2.7.1",
+    "redis": "^3.0.2",
     "redux": "^4.0.5",
     "redux-immutable": "^4.0.0",
     "redux-thunk": "^2.2.0",
@@ -154,7 +154,7 @@
     "requestidlecallback": "^0.3.0",
     "reselect": "^4.0.0",
     "rimraf": "^3.0.2",
-    "sass": "^1.25.0",
+    "sass": "^1.26.3",
     "sass-loader": "^8.0.2",
     "stacktrace-js": "^2.0.2",
     "stringz": "^2.0.0",
@@ -170,22 +170,22 @@
     "webpack-bundle-analyzer": "^3.6.0",
     "webpack-cli": "^3.3.11",
     "webpack-merge": "^4.2.1",
-    "wicg-inert": "^3.0.0"
+    "wicg-inert": "^3.0.2"
   },
   "devDependencies": {
     "babel-eslint": "^10.0.3",
-    "babel-jest": "^24.9.0",
+    "babel-jest": "^25.1.0",
     "enzyme": "^3.11.0",
     "enzyme-adapter-react-16": "^1.15.2",
     "eslint": "^6.8.0",
     "eslint-plugin-import": "~2.20.1",
     "eslint-plugin-jsx-a11y": "~6.2.3",
     "eslint-plugin-promise": "~4.2.1",
-    "eslint-plugin-react": "~7.17.0",
+    "eslint-plugin-react": "~7.19.0",
     "jest": "^24.9.0",
     "raf": "^3.4.1",
     "react-intl-translations-manager": "^5.0.3",
-    "react-test-renderer": "^16.12.0",
+    "react-test-renderer": "^16.13.0",
     "sass-lint": "^1.13.1",
     "webpack-dev-server": "^3.10.3",
     "yargs": "^15.1.0"
diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb
index b428299ee..49d3e9707 100644
--- a/spec/controllers/admin/reports_controller_spec.rb
+++ b/spec/controllers/admin/reports_controller_spec.rb
@@ -46,6 +46,26 @@ describe Admin::ReportsController do
     end
   end
 
+  describe 'POST #resolve' do
+    it 'resolves the report' do
+      report = Fabricate(:report)
+
+      put :resolve, params: { id: report }
+      expect(response).to redirect_to(admin_reports_path)
+      report.reload
+      expect(report.action_taken_by_account).to eq user.account
+      expect(report.action_taken).to eq true
+    end
+
+    it 'sets trust level when the report is an antispam one' do
+      report = Fabricate(:report, account: Account.representative)
+
+      put :resolve, params: { id: report }
+      report.reload
+      expect(report.target_account.trust_level).to eq Account::TRUST_LEVELS[:trusted]
+    end
+  end
+
   describe 'POST #reopen' do
     it 'reopens the report' do
       report = Fabricate(:report)
diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index 6fbceca53..40ddf1f95 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -15,7 +15,7 @@ ActiveRecord::Migration.maintain_test_schema!
 WebMock.disable_net_connect!(allow: Chewy.settings[:host])
 Redis.current = Redis::Namespace.new("mastodon_test#{ENV['TEST_ENV_NUMBER']}", redis: Redis.current)
 Sidekiq::Testing.inline!
-Sidekiq::Logging.logger = nil
+Sidekiq.logger = nil
 
 Devise::Test::ControllerHelpers.module_eval do
   alias_method :original_sign_in, :sign_in
diff --git a/yarn.lock b/yarn.lock
index aaacea167..f562cf45f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -18,7 +18,7 @@
     invariant "^2.2.4"
     semver "^5.5.0"
 
-"@babel/core@^7.1.0", "@babel/core@^7.4.5", "@babel/core@^7.8.6":
+"@babel/core@^7.1.0", "@babel/core@^7.4.5", "@babel/core@^7.7.5", "@babel/core@^7.8.6":
   version "7.8.6"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.6.tgz#27d7df9258a45c2e686b6f18b6c659e563aa4636"
   integrity sha512-Sheg7yEJD51YHAvLEV/7Uvw95AeWqYPL3Vk3zGujJKIhJ+8oLw2ALaf3hbucILhKsgSoADOvtKRJuNVdcJkOrg==
@@ -261,7 +261,7 @@
     esutils "^2.0.2"
     js-tokens "^4.0.0"
 
-"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.8.6":
+"@babel/parser@^7.0.0", "@babel/parser@^7.1.0", "@babel/parser@^7.7.5", "@babel/parser@^7.8.6":
   version "7.8.6"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.6.tgz#ba5c9910cddb77685a008e3c587af8d27b67962c"
   integrity sha512-trGNYSfwq5s0SgM1BMEB8hX3NDmO7EP2wsDGDexiaKMB92BaRpS+qZfpkMqUBhcsOTBwNy9B/jieo4ad/t/z2g==
@@ -355,6 +355,13 @@
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.0"
 
+"@babel/plugin-syntax-bigint@^7.0.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea"
+  integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==
+  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"
@@ -787,6 +794,14 @@
     "@babel/plugin-transform-react-jsx-self" "^7.8.3"
     "@babel/plugin-transform-react-jsx-source" "^7.8.3"
 
+"@babel/runtime-corejs3@^7.8.3":
+  version "7.8.7"
+  resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.8.7.tgz#8209d9dff2f33aa2616cb319c83fe159ffb07b8c"
+  integrity sha512-sc7A+H4I8kTd7S61dgB9RomXu/C+F4IrRr4Ytze4dnfx7AXEpCrejSNpjx7vq6y/Bak9S6Kbk65a/WgMLtg43Q==
+  dependencies:
+    core-js-pure "^3.0.0"
+    regenerator-runtime "^0.13.4"
+
 "@babel/runtime@7.0.0":
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c"
@@ -808,7 +823,7 @@
   dependencies:
     regenerator-runtime "^0.13.2"
 
-"@babel/template@^7.0.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
+"@babel/template@^7.0.0", "@babel/template@^7.7.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==
@@ -817,7 +832,7 @@
     "@babel/parser" "^7.8.6"
     "@babel/types" "^7.8.6"
 
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6":
+"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.7.4", "@babel/traverse@^7.8.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6":
   version "7.8.6"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff"
   integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A==
@@ -936,6 +951,21 @@
   resolved "https://registry.yarnpkg.com/@gamestdio/websocket/-/websocket-0.3.2.tgz#321ba0976ee30fd14e51dbf8faa85ce7b325f76a"
   integrity sha512-J3n5SKim+ZoLbe44hRGI/VYAwSMCeIJuBy+FfP6EZaujEpNchPRFcIsVQLWAwpU1bP2Ji63rC+rEUOd1vjUB6Q==
 
+"@istanbuljs/load-nyc-config@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz#10602de5570baea82f8afbfa2630b24e7a8cfe5b"
+  integrity sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==
+  dependencies:
+    camelcase "^5.3.1"
+    find-up "^4.1.0"
+    js-yaml "^3.13.1"
+    resolve-from "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2":
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
+  integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
+
 "@jest/console@^24.7.1":
   version "24.7.1"
   resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545"
@@ -1093,6 +1123,28 @@
     source-map "^0.6.1"
     write-file-atomic "2.4.1"
 
+"@jest/transform@^25.1.0":
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-25.1.0.tgz#221f354f512b4628d88ce776d5b9e601028ea9da"
+  integrity sha512-4ktrQ2TPREVeM+KxB4zskAT84SnmG1vaz4S+51aTefyqn3zocZUnliLLm5Fsl85I3p/kFPN4CRp1RElIfXGegQ==
+  dependencies:
+    "@babel/core" "^7.1.0"
+    "@jest/types" "^25.1.0"
+    babel-plugin-istanbul "^6.0.0"
+    chalk "^3.0.0"
+    convert-source-map "^1.4.0"
+    fast-json-stable-stringify "^2.0.0"
+    graceful-fs "^4.2.3"
+    jest-haste-map "^25.1.0"
+    jest-regex-util "^25.1.0"
+    jest-util "^25.1.0"
+    micromatch "^4.0.2"
+    pirates "^4.0.1"
+    realpath-native "^1.1.0"
+    slash "^3.0.0"
+    source-map "^0.6.1"
+    write-file-atomic "^3.0.0"
+
 "@jest/types@^24.9.0":
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59"
@@ -1102,6 +1154,21 @@
     "@types/istanbul-reports" "^1.1.1"
     "@types/yargs" "^13.0.0"
 
+"@jest/types@^25.1.0":
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.1.0.tgz#b26831916f0d7c381e11dbb5e103a72aed1b4395"
+  integrity sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==
+  dependencies:
+    "@types/istanbul-lib-coverage" "^2.0.0"
+    "@types/istanbul-reports" "^1.1.1"
+    "@types/yargs" "^15.0.0"
+    chalk "^3.0.0"
+
+"@rails/ujs@^6.0.2":
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/@rails/ujs/-/ujs-6.0.2.tgz#8d32452d51c5e115374a218fb5475803dc17f4c0"
+  integrity sha512-KSQjJG8yzSWC1IT+UtFQglefABU37hpJ7uAz39K1/iWtoaJaI9ydGIaxxpJBT/PmYv4kS6lCSjXq13DELeJocw==
+
 "@types/babel__core@^7.1.0", "@types/babel__core@^7.1.2":
   version "7.1.3"
   resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30"
@@ -1218,6 +1285,13 @@
   dependencies:
     "@types/yargs-parser" "*"
 
+"@types/yargs@^15.0.0":
+  version "15.0.4"
+  resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.4.tgz#7e5d0f8ca25e9d5849f2ea443cf7c402decd8299"
+  integrity sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==
+  dependencies:
+    "@types/yargs-parser" "*"
+
 "@webassemblyjs/ast@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
@@ -1571,6 +1645,14 @@ ansi-styles@^4.0.0:
     "@types/color-name" "^1.1.1"
     color-convert "^2.0.1"
 
+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"
+
 anymatch@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
@@ -1587,6 +1669,14 @@ anymatch@^3.0.1:
     normalize-path "^3.0.0"
     picomatch "^2.0.4"
 
+anymatch@^3.0.3:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
+  integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+  dependencies:
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
+
 aproba@^1.0.3, aproba@^1.1.1:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -1848,6 +1938,19 @@ babel-jest@^24.9.0:
     chalk "^2.4.2"
     slash "^2.0.0"
 
+babel-jest@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.1.0.tgz#206093ac380a4b78c4404a05b3277391278f80fb"
+  integrity sha512-tz0VxUhhOE2y+g8R2oFrO/2VtVjA1lkJeavlhExuRBg3LdNJY9gwQ+Vcvqt9+cqy71MCTJhewvTB7Qtnnr9SWg==
+  dependencies:
+    "@jest/transform" "^25.1.0"
+    "@jest/types" "^25.1.0"
+    "@types/babel__core" "^7.1.0"
+    babel-plugin-istanbul "^6.0.0"
+    babel-preset-jest "^25.1.0"
+    chalk "^3.0.0"
+    slash "^3.0.0"
+
 babel-loader@^8.0.6:
   version "8.0.6"
   resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb"
@@ -1890,6 +1993,17 @@ babel-plugin-istanbul@^5.1.0:
     istanbul-lib-instrument "^3.0.0"
     test-exclude "^5.0.0"
 
+babel-plugin-istanbul@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765"
+  integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@istanbuljs/load-nyc-config" "^1.0.0"
+    "@istanbuljs/schema" "^0.1.2"
+    istanbul-lib-instrument "^4.0.0"
+    test-exclude "^6.0.0"
+
 babel-plugin-jest-hoist@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756"
@@ -1897,6 +2011,13 @@ babel-plugin-jest-hoist@^24.9.0:
   dependencies:
     "@types/babel__traverse" "^7.0.6"
 
+babel-plugin-jest-hoist@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.1.0.tgz#fb62d7b3b53eb36c97d1bc7fec2072f9bd115981"
+  integrity sha512-oIsopO41vW4YFZ9yNYoLQATnnN46lp+MZ6H4VvPKFkcc2/fkl3CfE/NZZSmnEIEsJRmJAgkVEK0R7Zbl50CpTw==
+  dependencies:
+    "@types/babel__traverse" "^7.0.6"
+
 babel-plugin-lodash@^3.3.4:
   version "3.3.4"
   resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz#4f6844358a1340baed182adbeffa8df9967bc196"
@@ -1955,6 +2076,15 @@ babel-preset-jest@^24.9.0:
     "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
     babel-plugin-jest-hoist "^24.9.0"
 
+babel-preset-jest@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-25.1.0.tgz#d0aebfebb2177a21cde710996fce8486d34f1d33"
+  integrity sha512-eCGn64olaqwUMaugXsTtGAM2I0QTahjEtnRu0ql8Ie+gDWAc1N6wqN0k2NilnyTunM69Pad7gJY7LOtwLimoFQ==
+  dependencies:
+    "@babel/plugin-syntax-bigint" "^7.0.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.0.0"
+    babel-plugin-jest-hoist "^25.1.0"
+
 babel-runtime@^6.26.0:
   version "6.26.0"
   resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
@@ -2105,7 +2235,7 @@ braces@^2.3.1, braces@^2.3.2:
     split-string "^3.0.2"
     to-regex "^3.0.1"
 
-braces@^3.0.2:
+braces@^3.0.1, braces@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
   integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@@ -2408,6 +2538,14 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
     strip-ansi "^3.0.0"
     supports-color "^2.0.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"
@@ -2819,6 +2957,11 @@ core-js-compat@^3.6.2:
     browserslist "^4.8.3"
     semver "7.0.0"
 
+core-js-pure@^3.0.0:
+  version "3.6.4"
+  resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.4.tgz#4bf1ba866e25814f149d4e9aaa08c36173506e3a"
+  integrity sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==
+
 core-js@^2.4.0:
   version "2.6.1"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.1.tgz#87416ae817de957a3f249b3b5ca475d4aaed6042"
@@ -2891,12 +3034,12 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
     safe-buffer "^5.0.1"
     sha.js "^2.4.8"
 
-cross-env@^6.0.3:
-  version "6.0.3"
-  resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941"
-  integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==
+cross-env@^7.0.2:
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.2.tgz#bd5ed31339a93a3418ac4f3ca9ca3403082ae5f9"
+  integrity sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==
   dependencies:
-    cross-spawn "^7.0.0"
+    cross-spawn "^7.0.1"
 
 cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
   version "6.0.5"
@@ -2909,7 +3052,7 @@ cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
     shebang-command "^1.2.0"
     which "^1.2.9"
 
-cross-spawn@^7.0.0:
+cross-spawn@^7.0.1:
   version "7.0.1"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
   integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
@@ -3330,6 +3473,11 @@ delegates@^1.0.0:
   resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
   integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
 
+denque@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf"
+  integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==
+
 depd@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@@ -3521,11 +3669,6 @@ dotenv@^8.2.0:
   resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
   integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
 
-double-ended-queue@^2.1.0-0:
-  version "2.1.0-0"
-  resolved "https://registry.yarnpkg.com/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz#103d3527fd31528f40188130c841efdd78264e5c"
-  integrity sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=
-
 duplexer@^0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
@@ -3596,6 +3739,11 @@ emojis-list@^2.0.0:
   resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
   integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
 
+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"
@@ -3706,7 +3854,7 @@ error-stack-parser@^2.0.6:
   dependencies:
     stackframe "^1.1.1"
 
-es-abstract@^1.13.0, es-abstract@^1.15.0, es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.5.1:
+es-abstract@^1.13.0, es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.5.1:
   version "1.17.0"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.0.tgz#f42a517d0036a5591dbb2c463591dc8bb50309b1"
   integrity sha512-yYkE07YF+6SIBmg1MsJ9dlub5L48Ek7X0qz+c/CPCHS9EBXfESorzng4cJQjJW5/pB6vDF41u7F8vUhLVDqIug==
@@ -3864,11 +4012,6 @@ eslint-module-utils@^2.4.1:
     debug "^2.6.9"
     pkg-dir "^2.0.0"
 
-eslint-plugin-eslint-plugin@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-plugin/-/eslint-plugin-eslint-plugin-2.1.0.tgz#a7a00f15a886957d855feacaafee264f039e62d5"
-  integrity sha512-kT3A/ZJftt28gbl/Cv04qezb/NQ1dwYIbi8lyf806XMxkus7DvOVCLIfTXMrorp322Pnoez7+zabXH29tADIDg==
-
 eslint-plugin-import@~2.20.1:
   version "2.20.1"
   resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3"
@@ -3907,21 +4050,23 @@ eslint-plugin-promise@~4.2.1:
   resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
   integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
 
-eslint-plugin-react@~7.17.0:
-  version "7.17.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.17.0.tgz#a31b3e134b76046abe3cd278e7482bd35a1d12d7"
-  integrity sha512-ODB7yg6lxhBVMeiH1c7E95FLD4E/TwmFjltiU+ethv7KPdCwgiFuOZg9zNRHyufStTDLl/dEFqI2Q1VPmCd78A==
+eslint-plugin-react@~7.19.0:
+  version "7.19.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.19.0.tgz#6d08f9673628aa69c5559d33489e855d83551666"
+  integrity sha512-SPT8j72CGuAP+JFbT0sJHOB80TX/pu44gQ4vXH/cq+hQTiY2PuZ6IHkqXJV6x1b28GDdo1lbInjKUrrdUf0LOQ==
   dependencies:
-    array-includes "^3.0.3"
+    array-includes "^3.1.1"
     doctrine "^2.1.0"
-    eslint-plugin-eslint-plugin "^2.1.0"
     has "^1.0.3"
     jsx-ast-utils "^2.2.3"
-    object.entries "^1.1.0"
-    object.fromentries "^2.0.1"
-    object.values "^1.1.0"
+    object.entries "^1.1.1"
+    object.fromentries "^2.0.2"
+    object.values "^1.1.1"
     prop-types "^15.7.2"
-    resolve "^1.13.1"
+    resolve "^1.15.1"
+    semver "^6.3.0"
+    string.prototype.matchall "^4.0.2"
+    xregexp "^4.3.0"
 
 eslint-scope@^4.0.3:
   version "4.0.3"
@@ -4359,12 +4504,12 @@ file-entry-cache@^5.0.1:
   dependencies:
     flat-cache "^2.0.1"
 
-file-loader@^5.0.2:
-  version "5.0.2"
-  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-5.0.2.tgz#7f3d8b4ac85a5e8df61338cfec95d7405f971caa"
-  integrity sha512-QMiQ+WBkGLejKe81HU8SZ9PovsU/5uaLo0JdTCEXOYv7i7jfAjHZi1tcwp9tSASJPOmmHZtbdCervFmXMH/Dcg==
+file-loader@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-5.1.0.tgz#cb56c070efc0e40666424309bd0d9e45ac6f2bb8"
+  integrity sha512-u/VkLGskw3Ue59nyOwUwXI/6nuBCo7KBkniB/l7ICwr/7cPNGsL1WCXUp3GB0qgOOKU1TiP49bv4DZF/LJqprg==
   dependencies:
-    loader-utils "^1.2.3"
+    loader-utils "^1.4.0"
     schema-utils "^2.5.0"
 
 file-type@^10.5.0:
@@ -4624,6 +4769,11 @@ fsevents@^2.0.6:
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a"
   integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==
 
+fsevents@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
+  integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
+
 function-bind@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -4844,7 +4994,7 @@ graceful-fs@^4.1.6:
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
   integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
 
-graceful-fs@^4.2.2:
+graceful-fs@^4.2.2, graceful-fs@^4.2.3:
   version "4.2.3"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
   integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
@@ -5370,6 +5520,15 @@ internal-ip@^4.3.0:
     default-gateway "^4.2.0"
     ipaddr.js "^1.9.0"
 
+internal-slot@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.2.tgz#9c2e9fb3cd8e5e4256c6f45fe310067fcfa378a3"
+  integrity sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==
+  dependencies:
+    es-abstract "^1.17.0-next.1"
+    has "^1.0.3"
+    side-channel "^1.0.2"
+
 interpret@1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
@@ -5772,7 +5931,7 @@ is-symbol@^1.0.2:
   dependencies:
     has-symbols "^1.0.1"
 
-is-typedarray@~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=
@@ -5834,6 +5993,11 @@ istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.3:
   resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#0b891e5ad42312c2b9488554f603795f9a2211ba"
   integrity sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw==
 
+istanbul-lib-coverage@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec"
+  integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==
+
 istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz#a2b5484a7d445f1f311e93190813fa56dfb62971"
@@ -5847,6 +6011,19 @@ istanbul-lib-instrument@^3.0.0, istanbul-lib-instrument@^3.0.1:
     istanbul-lib-coverage "^2.0.3"
     semver "^5.5.0"
 
+istanbul-lib-instrument@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz#61f13ac2c96cfefb076fe7131156cc05907874e6"
+  integrity sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==
+  dependencies:
+    "@babel/core" "^7.7.5"
+    "@babel/parser" "^7.7.5"
+    "@babel/template" "^7.7.4"
+    "@babel/traverse" "^7.7.4"
+    "@istanbuljs/schema" "^0.1.2"
+    istanbul-lib-coverage "^3.0.0"
+    semver "^6.3.0"
+
 istanbul-lib-report@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz#bfd324ee0c04f59119cb4f07dab157d09f24d7e4"
@@ -6000,6 +6177,24 @@ jest-haste-map@^24.9.0:
   optionalDependencies:
     fsevents "^1.2.7"
 
+jest-haste-map@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-25.1.0.tgz#ae12163d284f19906260aa51fd405b5b2e5a4ad3"
+  integrity sha512-/2oYINIdnQZAqyWSn1GTku571aAfs8NxzSErGek65Iu5o8JYb+113bZysRMcC/pjE5v9w0Yz+ldbj9NxrFyPyw==
+  dependencies:
+    "@jest/types" "^25.1.0"
+    anymatch "^3.0.3"
+    fb-watchman "^2.0.0"
+    graceful-fs "^4.2.3"
+    jest-serializer "^25.1.0"
+    jest-util "^25.1.0"
+    jest-worker "^25.1.0"
+    micromatch "^4.0.2"
+    sane "^4.0.3"
+    walker "^1.0.7"
+  optionalDependencies:
+    fsevents "^2.1.2"
+
 jest-jasmine2@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0"
@@ -6076,6 +6271,11 @@ jest-regex-util@^24.9.0:
   resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636"
   integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==
 
+jest-regex-util@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.1.0.tgz#efaf75914267741838e01de24da07b2192d16d87"
+  integrity sha512-9lShaDmDpqwg+xAd73zHydKrBbbrIi08Kk9YryBEBybQFg/lBWR/2BDjjiSE7KIppM9C5+c03XiDaZ+m4Pgs1w==
+
 jest-resolve-dependencies@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab"
@@ -6155,6 +6355,11 @@ jest-serializer@^24.9.0:
   resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73"
   integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==
 
+jest-serializer@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-25.1.0.tgz#73096ba90e07d19dec4a0c1dd89c355e2f129e5d"
+  integrity sha512-20Wkq5j7o84kssBwvyuJ7Xhn7hdPeTXndnwIblKDR2/sy1SUm6rWWiG9kSCgJPIfkDScJCIsTtOKdlzfIHOfKA==
+
 jest-snapshot@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba"
@@ -6192,6 +6397,16 @@ jest-util@^24.9.0:
     slash "^2.0.0"
     source-map "^0.6.0"
 
+jest-util@^25.1.0:
+  version "25.1.0"
+  resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.1.0.tgz#7bc56f7b2abd534910e9fa252692f50624c897d9"
+  integrity sha512-7did6pLQ++87Qsj26Fs/TIwZMUFBXQ+4XXSodRNy3luch2DnRXsSnmpVtxxQ0Yd6WTipGpbhh2IFP1mq6/fQGw==
+  dependencies:
+    "@jest/types" "^25.1.0"
+    chalk "^3.0.0"
+    is-ci "^2.0.0"
+    mkdirp "^0.5.1"
+
 jest-validate@^24.9.0:
   version "24.9.0"
   resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab"
@@ -6530,7 +6745,7 @@ loader-utils@0.2.x:
     json5 "^0.5.0"
     object-assign "^4.0.1"
 
-loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
+loader-utils@1.2.3:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
   integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
@@ -6539,6 +6754,15 @@ loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.
     emojis-list "^2.0.0"
     json5 "^1.0.1"
 
+loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, 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"
+
 locate-path@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -6794,6 +7018,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4:
     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"
@@ -6967,6 +7199,11 @@ mkdirp@^0.5, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
   dependencies:
     minimist "0.0.8"
 
+mkdirp@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea"
+  integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==
+
 moo@^0.4.3:
   version "0.4.3"
   resolved "https://registry.yarnpkg.com/moo/-/moo-0.4.3.tgz#3f847a26f31cf625a956a87f2b10fbc013bfd10e"
@@ -7345,16 +7582,6 @@ object.entries@^1.1.0, object.entries@^1.1.1:
     function-bind "^1.1.1"
     has "^1.0.3"
 
-object.fromentries@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.1.tgz#050f077855c7af8ae6649f45c80b16ee2d31e704"
-  integrity sha512-PUQv8Hbg3j2QX0IQYv3iAGCbGcu4yY4KQ92/dhA4sFSixBmSmp13UpDLs6jGK8rBtbmhNNIK99LD2k293jpiGA==
-  dependencies:
-    define-properties "^1.1.3"
-    es-abstract "^1.15.0"
-    function-bind "^1.1.1"
-    has "^1.0.3"
-
 object.fromentries@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.2.tgz#4a09c9b9bb3843dd0f89acdb517a794d4f355ac9"
@@ -7866,6 +8093,11 @@ picomatch@^2.0.4:
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
   integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
 
+picomatch@^2.0.5:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
+  integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
+
 pify@^2.0.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
@@ -8549,11 +8781,6 @@ railroad-diagrams@^1.0.0:
   resolved "https://registry.yarnpkg.com/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e"
   integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=
 
-rails-ujs@^5.2.4:
-  version "5.2.4"
-  resolved "https://registry.yarnpkg.com/rails-ujs/-/rails-ujs-5.2.4.tgz#31056ccd62d868f7d044395f31d77a4440550ceb"
-  integrity sha512-Mzu6bnTBKn4IuJvP7BDJRy4lzvR1zMWVDeTdPwDubXBfxpFEKqwOi5Nb6tfE2SYtTd+bb3PRETf40I94jgKw3w==
-
 randexp@0.4.6:
   version "0.4.6"
   resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3"
@@ -8602,15 +8829,15 @@ rc@^1.2.7:
     minimist "^1.2.0"
     strip-json-comments "~2.0.1"
 
-react-dom@^16.12.0:
-  version "16.12.0"
-  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.12.0.tgz#0da4b714b8d13c2038c9396b54a92baea633fe11"
-  integrity sha512-LMxFfAGrcS3kETtQaCkTKjMiifahaMySFDn71fZUNpPHZQEzmk/GiAeIT8JSOrHB23fnuCOMruL2a8NYlw+8Gw==
+react-dom@^16.13.0:
+  version "16.13.0"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.0.tgz#cdde54b48eb9e8a0ca1b3dc9943d9bb409b81866"
+  integrity sha512-y09d2c4cG220DzdlFkPTnVvGTszVvNpC73v+AaLGLHbkpy3SSgvYq8x0rNwPJ/Rk/CicTNgk0hbHNw1gMEZAXg==
   dependencies:
     loose-envify "^1.1.0"
     object-assign "^4.1.1"
     prop-types "^15.6.2"
-    scheduler "^0.18.0"
+    scheduler "^0.19.0"
 
 react-event-listener@^0.6.0:
   version "0.6.5"
@@ -8632,10 +8859,12 @@ react-hotkeys@^1.1.4:
     mousetrap "^1.5.2"
     prop-types "^15.6.0"
 
-react-immutable-proptypes@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.1.0.tgz#023d6f39bb15c97c071e9e60d00d136eac5fa0b4"
-  integrity sha1-Aj1vObsVyXwHHp5g0A0TbqxfoLQ=
+react-immutable-proptypes@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/react-immutable-proptypes/-/react-immutable-proptypes-2.2.0.tgz#cce96d68cc3c18e89617cbf3092d08e35126af4a"
+  integrity sha512-Vf4gBsePlwdGvSZoLSBfd4HAP93HDauMY4fDjXhreg/vg6F3Fj/MXDNyTbltPC/xZKmZc+cjLu3598DdYK6sgQ==
+  dependencies:
+    invariant "^2.2.2"
 
 react-immutable-pure-component@^1.1.1:
   version "1.2.3"
@@ -8830,15 +9059,15 @@ react-swipeable-views@^0.13.9:
     react-swipeable-views-utils "^0.13.9"
     warning "^4.0.1"
 
-react-test-renderer@^16.0.0-0, react-test-renderer@^16.12.0:
-  version "16.12.0"
-  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.12.0.tgz#11417ffda579306d4e841a794d32140f3da1b43f"
-  integrity sha512-Vj/teSqt2oayaWxkbhQ6gKis+t5JrknXfPVo+aIJ8QwYAqMPH77uptOdrlphyxl8eQI/rtkOYg86i/UWkpFu0w==
+react-test-renderer@^16.0.0-0, react-test-renderer@^16.13.0:
+  version "16.13.0"
+  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.13.0.tgz#39ba3bf72cedc8210c3f81983f0bb061b14a3014"
+  integrity sha512-NQ2S9gdMUa7rgPGpKGyMcwl1d6D9MCF0lftdI3kts6kkiX+qvpC955jNjAZXlIDTjnN9jwFI8A8XhRh/9v0spA==
   dependencies:
     object-assign "^4.1.1"
     prop-types "^15.6.2"
     react-is "^16.8.6"
-    scheduler "^0.18.0"
+    scheduler "^0.19.0"
 
 react-textarea-autosize@^7.1.2:
   version "7.1.2"
@@ -8962,24 +9191,32 @@ realpath-native@^1.1.0:
   dependencies:
     util.promisify "^1.0.0"
 
-redis-commands@^1.2.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.4.0.tgz#52f9cf99153efcce56a8f86af986bd04e988602f"
-  integrity sha512-cu8EF+MtkwI4DLIT0x9P8qNTLFhQD4jLfxLR0cCNkeGzs87FN6879JOJwNQR/1zD7aSYNbU0hgsV9zGY71Itvw==
+redis-commands@^1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.5.0.tgz#80d2e20698fe688f227127ff9e5164a7dd17e785"
+  integrity sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==
 
-redis-parser@^2.6.0:
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-2.6.0.tgz#52ed09dacac108f1a631c07e9b69941e7a19504b"
-  integrity sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=
+redis-errors@^1.0.0, redis-errors@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
+  integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=
 
-redis@^2.7.1:
-  version "2.8.0"
-  resolved "https://registry.yarnpkg.com/redis/-/redis-2.8.0.tgz#202288e3f58c49f6079d97af7a10e1303ae14b02"
-  integrity sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==
+redis-parser@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
+  integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=
   dependencies:
-    double-ended-queue "^2.1.0-0"
-    redis-commands "^1.2.0"
-    redis-parser "^2.6.0"
+    redis-errors "^1.0.0"
+
+redis@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/redis/-/redis-3.0.2.tgz#bd47067b8a4a3e6a2e556e57f71cc82c7360150a"
+  integrity sha512-PNhLCrjU6vKVuMOyFu7oSP296mwBkcE6lrAjruBYG5LgdSqtRBoVQIylrMyVZD/lkF24RSNNatzvYag6HRBHjQ==
+  dependencies:
+    denque "^1.4.1"
+    redis-commands "^1.5.0"
+    redis-errors "^1.2.0"
+    redis-parser "^3.0.0"
 
 redux-immutable@^4.0.0:
   version "4.0.0"
@@ -9031,6 +9268,11 @@ regenerator-runtime@^0.13.2:
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
   integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
 
+regenerator-runtime@^0.13.4:
+  version "0.13.4"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz#e96bf612a3362d12bb69f7e8f74ffeab25c7ac91"
+  integrity sha512-plpwicqEzfEyTQohIKktWigcLzmNStMGwbOUbykx51/29Z3JOGYldaaNGK7ngNXV+UcoqvIMmloZ48Sr74sd+g==
+
 regenerator-transform@^0.14.0:
   version "0.14.0"
   resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf"
@@ -9053,6 +9295,14 @@ regexp.prototype.flags@^1.2.0:
   dependencies:
     define-properties "^1.1.2"
 
+regexp.prototype.flags@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75"
+  integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+
 regexpp@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
@@ -9222,6 +9472,11 @@ resolve-from@^4.0.0:
   resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
   integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
 
+resolve-from@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+  integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
 resolve-pathname@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879"
@@ -9242,10 +9497,10 @@ resolve@1.1.7:
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
   integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
 
-resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1:
-  version "1.13.1"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16"
-  integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w==
+resolve@^1.12.0, resolve@^1.15.1, resolve@^1.3.2, resolve@^1.5.0, resolve@^1.8.1:
+  version "1.15.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8"
+  integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==
   dependencies:
     path-parse "^1.0.6"
 
@@ -9428,10 +9683,10 @@ sass-loader@^8.0.2:
     schema-utils "^2.6.1"
     semver "^6.3.0"
 
-sass@^1.25.0:
-  version "1.25.0"
-  resolved "https://registry.yarnpkg.com/sass/-/sass-1.25.0.tgz#f8bd7dfbb39d6b0305e27704a8ebe637820693f3"
-  integrity sha512-uQMjye0Y70SEDGO56n0j91tauqS9E1BmpKHtiYNQScXDHeaE9uHwNEqQNFf4Bes/3DHMNinB6u79JsG10XWNyw==
+sass@^1.26.3:
+  version "1.26.3"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.26.3.tgz#412df54486143b76b5a65cdf7569e86f44659f46"
+  integrity sha512-5NMHI1+YFYw4sN3yfKjpLuV9B5l7MqQ6FlkTcC4FT+oHbBRUZoSjHrrt/mE0nFXJyY2kQtU9ou9HxvFVjLFuuw==
   dependencies:
     chokidar ">=2.0.0 <4.0.0"
 
@@ -9448,6 +9703,14 @@ scheduler@^0.18.0:
     loose-envify "^1.1.0"
     object-assign "^4.1.1"
 
+scheduler@^0.19.0:
+  version "0.19.0"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.0.tgz#a715d56302de403df742f4a9be11975b32f5698d"
+  integrity sha512-xowbVaTPe9r7y7RUejcK73/j8tt2jfiyTednOvHbA8JoClvMYCp+r8QegLwK/n8zWQAtZb1fFnER4XLBZXrCxA==
+  dependencies:
+    loose-envify "^1.1.0"
+    object-assign "^4.1.1"
+
 schema-utils@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
@@ -9636,6 +9899,14 @@ shellwords@^0.1.1:
   resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
   integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==
 
+side-channel@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"
+  integrity sha512-7rL9YlPHg7Ancea1S96Pa8/QWb4BtXL/TZvS6B8XFetGBeuhAsfmUspK6DokBeZ64+Kj9TCNRD/30pVz1BvQNA==
+  dependencies:
+    es-abstract "^1.17.0-next.1"
+    object-inspect "^1.7.0"
+
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
@@ -9663,6 +9934,11 @@ slash@^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@0.0.4:
   version "0.0.4"
   resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
@@ -10021,6 +10297,18 @@ string-width@^4.1.0, string-width@^4.2.0:
     is-fullwidth-code-point "^3.0.0"
     strip-ansi "^6.0.0"
 
+string.prototype.matchall@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.2.tgz#48bb510326fb9fdeb6a33ceaa81a6ea04ef7648e"
+  integrity sha512-N/jp6O5fMf9os0JU3E72Qhf590RSRZU/ungsL/qJUYVTNv7hTG0P/dbPjxINVN9jpscu3nzYwKESU3P3RY5tOg==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0"
+    has-symbols "^1.0.1"
+    internal-slot "^1.0.2"
+    regexp.prototype.flags "^1.3.0"
+    side-channel "^1.0.2"
+
 string.prototype.trim@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.1.tgz#141233dff32c82bfad80684d7e5f0869ee0fb782"
@@ -10160,7 +10448,7 @@ supports-color@^5.3.0:
   dependencies:
     has-flag "^3.0.0"
 
-supports-color@^7.0.0:
+supports-color@^7.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==
@@ -10321,6 +10609,15 @@ test-exclude@^5.0.0:
     read-pkg-up "^4.0.0"
     require-main-filename "^1.0.1"
 
+test-exclude@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+  integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
+  dependencies:
+    "@istanbuljs/schema" "^0.1.2"
+    glob "^7.1.4"
+    minimatch "^3.0.4"
+
 text-table@^0.2.0, text-table@~0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -10522,6 +10819,13 @@ type@^2.0.0:
   resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3"
   integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==
 
+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"
@@ -11024,10 +11328,10 @@ which@^2.0.1:
   dependencies:
     isexe "^2.0.0"
 
-wicg-inert@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/wicg-inert/-/wicg-inert-3.0.0.tgz#4f5797172fbf7ff01effd3839b52872e35d3cba2"
-  integrity sha512-sZsYZ8pk8y6CgDLkTxivfhLDBvZuDWTWBawU8OuDdO0Id6AOd1Gqjkvt9g9Ni7rgHIS7UbRvbLSv1z7MSJDYCA==
+wicg-inert@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/wicg-inert/-/wicg-inert-3.0.2.tgz#46d8b01142c1bda8f6fa5d78e2754ba56f6f70be"
+  integrity sha512-L2eSi1fx1M+WLLUccwzAulgK5hZtllRDvYk3UB/fe1ZqdkZS6dz718o6xfe3JUtBEJJnqvI6NF8m1bAHlg3JUg==
 
 wide-align@^1.1.0:
   version "1.1.3"
@@ -11093,6 +11397,16 @@ write-file-atomic@2.4.1:
     imurmurhash "^0.1.4"
     signal-exit "^3.0.2"
 
+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"
@@ -11126,6 +11440,13 @@ xml-name-validator@^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==
 
+xregexp@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.3.0.tgz#7e92e73d9174a99a59743f67a4ce879a04b5ae50"
+  integrity sha512-7jXDIFXh5yJ/orPn4SXjuVrWWoi4Cr8jfV1eHv9CixKSbU+jY4mxfrBwAuDvupPNKpMUY+FeIqsVw/JLT9+B8g==
+  dependencies:
+    "@babel/runtime-corejs3" "^7.8.3"
+
 xtend@^4.0.0, xtend@~4.0.1:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"