diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 00000000..e94f8140 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1 @@ +defaults diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml new file mode 100644 index 00000000..ea36b050 --- /dev/null +++ b/.github/workflows/rubocop.yml @@ -0,0 +1,30 @@ +# https://github.com/rails/rails/blob/main/.github/workflows/rubocop.yml + +name: RuboCop + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Ruby 2.7 + uses: ruby/setup-ruby@v1 + with: + ruby-version: 2.7 + - name: Cache gems + uses: actions/cache@v1 + with: + path: vendor/bundle + key: ${{ runner.os }}-rubocop-${{ hashFiles('**/Gemfile.lock') }} + restore-keys: | + ${{ runner.os }}-rubocop- + - name: Install gems + run: | + bundle config path vendor/bundle + bundle config set without 'default doc job cable storage ujs test db' + bundle install --jobs 4 --retry 3 + - name: Run RuboCop + run: bundle exec rubocop --parallel diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..39686da3 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,57 @@ +name: test + +on: + push: + branches: [develop, main, master, "feature/**"] + pull_request: + branches: [develop, main, master, "feature/**"] + + # Allows workflow manually from the Actions tab + workflow_dispatch: + +jobs: + test: + runs-on: ubuntu-latest + services: + mysql: + image: mysql + env: + MYSQL_ROOT_PASSWORD: root + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + env: + DB_HOST: 127.0.0.1 + DB_PORT: 3306 + DB_USERNAME: root + DB_PASSWORD: root + RAILS_ENV: test + steps: + - name: Verify mysql connection + run: | + mysql --host ${{ ENV.DB_HOST }} --port ${{ ENV.DB_PORT }} -u${{ ENV.DB_USERNAME}} -p${{ ENV.DB_PASSWORD }} -e "SHOW DATABASES" + - uses: actions/checkout@v2 + - uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Install dependencies + run: | + gem install bundler + bundle install + yarn install --frozen-lockfile + - name: Setup config files for CI + run: | + cp config/ldap_ci.yml config/ldap.yml + - name: Setup Database + run: | + cp config/database_ci.yml config/database.yml + ./bin/rails db:create + ./bin/rails db:migrate + - name: Run RSpec + run: bundle exec rspec + - name: Archive capybara artifacts + uses: actions/upload-artifact@v2 + if: failure() + with: + name: capybara + path: tmp/capybara/ diff --git a/.gitignore b/.gitignore index a901bae0..16d74184 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,12 @@ config/ldap.yml config/database.yml config/secrets.yml + +.env* +!.env.example +/public/packs +/public/packs-test +/node_modules +/yarn-error.log +yarn-debug.log* +.yarn-integrity diff --git a/.rubocop.yml b/.rubocop.yml index 13d9a10f..139a7468 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,4 +1,52 @@ -inherit_from: ~/.rubocop.yml +inherit_from: .rubocop_todo.yml -Rails: - Enabled: true +require: + - rubocop-rspec + - rubocop-rails + - rubocop-rake + - rubocop-performance + +AllCops: + NewCops: enable + Exclude: + - db/schema.rb # autogenerated + - vendor/**/* # not our code + - bin/**/* # autogenerated + - node_modules/**/* + +Metrics/BlockLength: + Exclude: + - spec/**/* + - config/**/* + - db/migrate/* + - lib/tasks/**/* + +# perceived complexity cop forces us to avoid inlining code, +# even though inlining code makes code easier to reason with +# and less error prone +Metrics/PerceivedComplexity: + Enabled: false + +# cyclomatic complexity cop forces us to avoid inlining code, even though +# inlining code makes code easier to reason with and less error prone +Metrics/CyclomaticComplexity: + Enabled: false + +Metrics/ClassLength: + Enabled: false + +# explicit arguments are easier to understand / read without needing to read the docs +Style/RedundantArgument: + Enabled: false + +# Tests are self-documenting +Style/Documentation: + Exclude: + - spec/**/* + +# Multiple expects can make for faster E2E tests +RSpec/MultipleExpectations: + Enabled: false + +Style/StringLiterals: + Enabled: false diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..168c8ac5 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,340 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2021-08-17 13:25:14 UTC using RuboCop version 1.18.4. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 3 +Lint/DuplicateMethods: + Exclude: + - "app/models/user.rb" + - "app/policies/transfer_request_policy.rb" + +# Offense count: 1 +# Configuration parameters: AllowComments. +Lint/EmptyFile: + Exclude: + - "config/initializers/paper_trail.rb" + +# Offense count: 1 +# Cop supports --auto-correct. +# Lint/NonDeterministicRequireOrder: +# Exclude: +# - 'spec/rails_helper.rb' + +# Offense count: 22 +# Configuration parameters: IgnoredMethods, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 40 + +# Offense count: 2 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +# IgnoredMethods: refine +Metrics/BlockLength: + Max: 33 + +# Offense count: 2 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 113 + +# Offense count: 25 +# Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. +Metrics/MethodLength: + Max: 43 + +# Offense count: 4 +Naming/AccessorMethodName: + Exclude: + - "app/datatables/admin_url_datatable.rb" + - "app/datatables/audit_datatable.rb" + - "app/datatables/url_datatable.rb" + - "app/services/user_lookup_service_skeleton.rb" + +# Offense count: 5 +# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. +# AllowedNames: at, by, db, id, in, io, ip, of, on, os, pp, to +Naming/MethodParameterName: + Exclude: + - "app/services/user_lookup_service.rb" + +# Offense count: 1 +# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# ForbiddenPrefixes: is_, has_, have_ +# AllowedMethods: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - "app/controllers/sessions_controller.rb" + +# Offense count: 5 +RSpec/Capybara/VisibilityMatcher: + Exclude: + - "spec/features/group_to_urls_spec.rb" + - "spec/features/move_group_spec.rb" + - "spec/features/transfer_request_spec.rb" + +# Offense count: 29 +# Configuration parameters: IgnoredMetadata. +RSpec/DescribeClass: + Enabled: false + +# Offense count: 31 +# Configuration parameters: CountAsOne. +RSpec/ExampleLength: + Max: 27 + +# Offense count: 2 +# Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly. +# Include: **/*_spec*rb*, **/spec/**/* +RSpec/FilePath: + Exclude: + - "spec/features/copy_short_url.rb" + - "spec/models/announcement_spec.rb" + +# Offense count: 364 +# Configuration parameters: AssignmentOnly. +RSpec/InstanceVariable: + Enabled: false + +# Offense count: 4 +RSpec/MultipleDescribes: + Exclude: + - "spec/features/admin/announcements_spec.rb" + - "spec/features/admin/audits_spec.rb" + - "spec/features/admin/urls_spec.rb" + - "spec/features/admin_members_spec.rb" + +# Offense count: 7 +# Configuration parameters: AllowSubject. +RSpec/MultipleMemoizedHelpers: + Max: 8 + +# Offense count: 18 +# Configuration parameters: IgnoreSharedExamples. +RSpec/NamedSubject: + Exclude: + - "spec/models/group_spec.rb" + - "spec/models/transfer_request_spec.rb" + - "spec/models/url_spec.rb" + - "spec/policies/admin_membership_policy_spec.rb" + - "spec/policies/audit_policy_spec.rb" + - "spec/policies/group_policy_spec.rb" + - "spec/policies/transfer_request_policy_spec.rb" + - "spec/policies/url_policy_spec.rb" + +# Offense count: 48 +RSpec/NestedGroups: + Max: 8 + +# Offense count: 2 +RSpec/OverwritingSetup: + Exclude: + - "spec/apis/urls_spec.rb" + +# Offense count: 52 +RSpec/RepeatedDescription: + Exclude: + - "spec/features/admin/audits_spec.rb" + - "spec/models/url_spec.rb" + - "spec/policies/url_policy_spec.rb" + +# Offense count: 6 +RSpec/RepeatedExample: + Exclude: + - "spec/models/url_spec.rb" + - "spec/policies/url_policy_spec.rb" + +# Offense count: 1 +# Cop supports --auto-correct. +Rails/ApplicationController: + Exclude: + - "app/controllers/api/v1/base_controller.rb" + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: Whitelist, AllowedMethods, AllowedReceivers. +# Whitelist: find_by_sql +# AllowedMethods: find_by_sql +# AllowedReceivers: Gem::Specification +Rails/DynamicFindBy: + Exclude: + - "app/helpers/sessions_helper.rb" + - "app/models/group.rb" + +# Offense count: 1 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: slashes, arguments +Rails/FilePath: + Exclude: + - "config/initializers/lograge.rb" + +# Offense count: 2 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/HasAndBelongsToMany: + Exclude: + - "app/models/transfer_request.rb" + - "app/models/url.rb" + +# Offense count: 1 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/HasManyOrHasOneDependent: + Exclude: + - "app/models/group.rb" + +# Offense count: 1 +# Configuration parameters: Include. +# Include: app/helpers/**/*.rb +Rails/HelperInstanceVariable: + Exclude: + - "app/helpers/sessions_helper.rb" + +# Offense count: 4 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/InverseOf: + Exclude: + - "app/models/audit.rb" + - "app/models/group.rb" + - "app/models/transfer_request.rb" + +# Offense count: 2 +# Configuration parameters: Include. +# Include: app/controllers/**/*.rb +Rails/LexicallyScopedActionFilter: + Exclude: + - "app/controllers/group_memberships_controller.rb" + - "app/controllers/transfer_requests_controller.rb" + +# Offense count: 3 +# Configuration parameters: ForbiddenMethods, AllowedMethods. +# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all +Rails/SkipsModelValidations: + Exclude: + - "app/controllers/move_to_group_controller.rb" + - "app/models/transfer_request.rb" + - "app/models/url.rb" + +# Offense count: 2 +# Configuration parameters: Environments. +# Environments: development, test, production +Rails/UnknownEnv: + Exclude: + - "config/initializers/omniauth.rb" + +# Offense count: 1 +# Cop supports --auto-correct. +Security/YAMLLoad: + Exclude: + - "app/services/user_lookup_service.rb" + +# Offense count: 2 +# Cop supports --auto-correct. +Style/CaseLikeIf: + Exclude: + - "app/services/user_lookup_service.rb" + - "app/services/user_lookup_service_skeleton.rb" + +# Offense count: 15 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: nested, compact +Style/ClassAndModuleChildren: + Exclude: + - "app/controllers/admin/admins_controller.rb" + - "app/controllers/admin/announcements_controller.rb" + - "app/controllers/admin/audits_controller.rb" + - "app/controllers/admin/audits_datatable_controller.rb" + - "app/controllers/admin/groups_controller.rb" + - "app/controllers/admin/members_controller.rb" + - "app/controllers/admin/transfer_requests_controller.rb" + - "app/controllers/admin/url_csvs_controller.rb" + - "app/controllers/admin/urls_controller.rb" + - "app/controllers/admin/urls_datatable_controller.rb" + - "app/controllers/api/v1/base_controller.rb" + - "app/controllers/api/v1/urls_controller.rb" + - "app/helpers/admin/announcements_helper.rb" + - "app/models/admin/announcement.rb" + - "app/policies/admin/announcement_policy.rb" + +# Offense count: 3 +Style/CombinableLoops: + Exclude: + - "app/models/group.rb" + - "app/models/transfer_request.rb" + - "app/models/url.rb" + +# Offense count: 59 +# Configuration parameters: AllowedConstants. +Style/Documentation: + Enabled: false + +# Offense count: 155 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Enabled: false + +# Offense count: 3 +# Cop supports --auto-correct. +Style/GlobalStdStream: + Exclude: + - "config/environments/production.rb" + - "config/environments/remotedev.rb" + - "config/environments/staging.rb" + +# Offense count: 5 +# Configuration parameters: MinBodyLength. +Style/GuardClause: + Exclude: + - "app/controllers/pages_controller.rb" + - "app/controllers/redirect_controller.rb" + - "app/helpers/sessions_helper.rb" + - "app/models/user.rb" + +# Offense count: 1 +# Cop supports --auto-correct. +Style/IfUnlessModifier: + Exclude: + - "app/helpers/sessions_helper.rb" + +# Offense count: 1 +Style/MultilineBlockChain: + Exclude: + - "app/helpers/group_helper.rb" + +# Offense count: 1 +# Configuration parameters: AllowedMethods. +# AllowedMethods: respond_to_missing? +Style/OptionalBooleanParameter: + Exclude: + - "app/models/group.rb" + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: SafeForConstants. +Style/RedundantFetchBlock: + Exclude: + - "config/puma.rb" + +# Offense count: 2 +# Cop supports --auto-correct. +# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods. +# AllowedMethods: present?, blank?, presence, try, try! +Style/SafeNavigation: + Exclude: + - "app/controllers/api/v1/base_controller.rb" + - "app/models/url.rb" + +# Offense count: 14 +# Cop supports --auto-correct. +# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 324 diff --git a/.ruby-version b/.ruby-version index 005119ba..2c9b4ef4 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.4.1 +2.7.3 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1c429779..00000000 --- a/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: ruby -rvm: - - 2.3.1 diff --git a/Dockerfile b/Dockerfile index bf8ca24d..2dacaea7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.3.3 +FROM ruby:2.7.3 RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs RUN mkdir /z WORKDIR /z diff --git a/Gemfile b/Gemfile index d3ebe195..724fb00e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,142 +1,167 @@ source 'https://rubygems.org' -gem 'passenger' +gem 'passenger', "~> 6.0" gem 'ajax-datatables-rails', github: 'jbox-web/ajax-datatables-rails', ref: '70513cb0e0990f26b52626ba13674e67104c03c6' # Use OmniAuth to support any type of auth -gem 'omniauth' -gem 'omniauth-shibboleth' -gem 'omniauth-shibboleth-passive' +gem 'omniauth', "~> 1.9" +gem 'omniauth-shibboleth', "~> 1.1" +gem 'omniauth-shibboleth-passive', "~> 0.1" # temporary hack due to mimemagic update # rails 5.2.5 seems to break the app?? # gem 'mimemagic', github: 'mimemagicrb/mimemagic', ref: '01f92d86d15d85cfd0f20dabd025dcbd36a8a60f' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 5.2.0' +gem 'rails', '~> 6.1' # Use mysql2 as the database for Active Record -gem 'mysql2' +gem 'mysql2', "~> 0.5" # Use sqlite also -gem 'sqlite3' +gem 'sqlite3', "~> 1.4" # Use Puma as the app server -gem 'puma', '~> 3.0' +gem 'puma', '~> 4.3' # Use SCSS for stylesheets gem 'sass-rails', '~> 5.0' # Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '>= 1.3.0' +gem 'uglifier', '~> 4.2' # Use CoffeeScript for .coffee assets and views -gem 'coffee-rails', '~> 4.2.0' +gem 'coffee-rails', '~> 4.2' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby -gem "lograge" +gem "lograge", "~> 0.11" # For javascript translations -gem "i18n-js" +gem "i18n-js", "~> 3.7" # Use jquery as the JavaScript library -gem 'jquery-rails' +gem 'jquery-rails', "~> 4.4" # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks -gem 'turbolinks', '~> 5.x' +gem 'turbolinks', '~> 5.2' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.0' +gem 'jbuilder', '~> 2.10' # Use this as the autocompleter library -gem 'twitter-typeahead-rails', git: 'git://github.com/pgate/twitter-typeahead-rails' +gem 'twitter-typeahead-rails', git: 'https://github.com/pgate/twitter-typeahead-rails.git' # Use net-ldap for LDAP lookup integration -gem 'net-ldap' +gem 'net-ldap', "~> 0.16" # Use bootstrap for styling -gem 'twitter-bootstrap-rails' +gem 'twitter-bootstrap-rails', git: 'https://github.com/seyhunak/twitter-bootstrap-rails.git' + # Use special bootstrap select -gem 'bootstrap-select-rails' -#Use font awesome for icons -gem "font-awesome-rails" +gem 'bootstrap-select-rails', "~> 1.13" +# Use font awesome for icons +gem "font-awesome-rails", "~> 4.7" -#Use clipboard js plugin -gem 'clipboard-rails' +# Use clipboard js plugin +gem 'clipboard-rails', "~> 1.7" # better confirm dialogs -gem 'data-confirm-modal' +gem 'data-confirm-modal', "~> 1.6" # use papertrail for auding or versioning -gem 'paper_trail' +gem 'paper_trail', "~> 12.0" # Use barby to generate QR codes -gem 'rqrcode' -gem 'barby' -gem 'chunky_png' +gem 'barby', "~> 0.6" +gem 'chunky_png', "~> 1.3" +gem 'rqrcode', "~> 1.1" # authorization lugin -gem 'pundit' +gem 'pundit', "~> 2.1" # announcements to the seething masses -# https://github.com/csm123/starburst# -gem 'starburst', git: 'git://github.com/csm123/starburst' +# Using our own fork of starburst to support Rails 6.1 for now +gem 'starburst', github: 'UMN-LATIS/starburst' -#notify someone when exceptions occur -#and notify slack channel -gem 'exception_notification' -gem 'slack-notifier' +# notify someone when exceptions occur +# and notify slack channel +gem 'exception_notification', "~> 4.4" +gem 'slack-notifier', "~> 2.3" # For URL migration -gem 'addressable' +gem 'addressable', "~> 2.8" # For API Authentication -gem 'jwt' +gem 'jwt', "~> 2.2" + +gem "sentry-rails", "~> 4.4" +gem "sentry-ruby", "~> 4.4" -gem "sentry-ruby" -gem "sentry-rails" +# Load ENV variables from .env file +gem 'dotenv-rails', "~> 2.7" group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a # debugger console - gem 'byebug', platform: :mri + gem 'byebug', "~> 11.1", platform: :mri + + # Use Rspec, capybara, and apparition for testing + gem 'capybara', "~> 3.15" + gem 'capybara-screenshot', "~> 1.0" + gem 'rspec-rails', "~> 4.0" + + # Using github for source until change in twalpole/apparition#79 + # is released. Change back to gem version after. + gem 'apparition', github: 'twalpole/apparition', ref: 'ca86be4' + gem 'database_cleaner', "~> 1.8" + gem 'factory_bot_rails', "~> 6.2" + gem 'fuubar', "~> 2.5" + gem 'launchy', "~> 2.4" - # Use Rspec, capybara, and poltergeist for testing - gem 'rspec-rails' - gem 'capybara' - gem 'poltergeist' - gem 'launchy' - gem 'factory_girl_rails' - gem 'database_cleaner' - gem 'fuubar' + # for retrying flaky tests until they can be fixed + gem "rspec-retry", "~> 0.6" + + # Watch files for changes and re-run tests + gem 'guard', "~> 2.17" + gem 'guard-rspec', "~> 4.7", require: false # Add some pry/rails console helpers for development - gem 'pry', '0.12.2' - gem 'pry-coolline' - gem 'pry-byebug' - gem 'awesome_print' - gem 'pry-rails' + gem 'awesome_print', "~> 1.8" + gem 'pry', '~> 0.13' + gem 'pry-byebug', "~> 3.9" + gem 'pry-rails', "~> 0.3" + gem 'shoulda-matchers', '~> 5.0' end group :development do # Access an IRB console on exception pages or by using <%= console %> anywhere # in the code. - gem 'web-console' - gem 'listen', '~> 3.0.5' + gem 'listen', '~> 3.0' + gem 'web-console', "~> 3.7" # Spring speeds up development by keeping your application running in the # background. Read more: https://github.com/rails/spring # Use better_errors to have more clear error messages and an interactive shell - gem 'better_errors' - gem 'binding_of_caller' + gem 'better_errors', "~> 2.7" + gem 'binding_of_caller', "~> 0.8" - # rubocop for styled code - gem 'rubocop', '~> 0.47.1', require: false + # rubocop for linting + gem 'rubocop', '~> 1.18', require: false + gem "rubocop-performance", "~> 1.11", require: false + gem "rubocop-rails", "~> 2.11", require: false + gem "rubocop-rake", "~> 0.6.0", require: false + gem "rubocop-rspec", "~> 2.4", require: false # Use annotate to list the attributes of models - gem 'annotate' - - gem 'capistrano' - gem 'capistrano-bundler' - gem 'capistrano-passenger', '>= 0.1.1' - gem 'capistrano-rbenv' - gem 'capistrano-rails' + gem 'annotate', "~> 3.1" + + gem 'bcrypt_pbkdf', "~> 1.1" + gem 'capistrano', "~> 3.14" + gem 'capistrano-bundler', "~> 1.6" + gem 'capistrano-passenger', '~> 0.2' + gem 'capistrano-rails', "~> 1.5" + gem 'capistrano-rbenv', "~> 2.1" + gem 'ed25519', "~> 1.2" end # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] +gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] + +gem 'browser', "~> 4.2" + +gem "webpacker", "~> 5.4" -gem 'browser' \ No newline at end of file +gem "rack-utf8_sanitizer", "~> 1.7" diff --git a/Gemfile.lock b/Gemfile.lock index e55bbff5..68a70c66 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,12 +1,20 @@ GIT - remote: git://github.com/csm123/starburst - revision: ff8fd1f8fbb7b466580a0f9484849c4de207e111 + remote: https://github.com/UMN-LATIS/starburst.git + revision: 6d3e0c0a8fef8d505e1a5fb43879ba3ea0a06c02 specs: starburst (2.0.0.rc0) - rails (>= 4.2.0, < 6.1) + rails (>= 4.2.0, < 6.2) GIT - remote: git://github.com/pgate/twitter-typeahead-rails + remote: https://github.com/jbox-web/ajax-datatables-rails.git + revision: 70513cb0e0990f26b52626ba13674e67104c03c6 + ref: 70513cb0e0990f26b52626ba13674e67104c03c6 + specs: + ajax-datatables-rails (0.4.3) + railties (>= 4.0) + +GIT + remote: https://github.com/pgate/twitter-typeahead-rails.git revision: 105a036048eb4c19a1d5c0bb7aec55346c8b506d specs: twitter-typeahead-rails (0.11.1) @@ -15,69 +23,98 @@ GIT railties (>= 3.1) GIT - remote: https://github.com/jbox-web/ajax-datatables-rails.git - revision: 70513cb0e0990f26b52626ba13674e67104c03c6 - ref: 70513cb0e0990f26b52626ba13674e67104c03c6 + remote: https://github.com/seyhunak/twitter-bootstrap-rails.git + revision: a9a5b41735cdb37e0dcb878eb25dcdf6174412cd specs: - ajax-datatables-rails (0.4.3) - railties (>= 4.0) + twitter-bootstrap-rails (4.0.0) + actionpack (>= 5.0, < 7.0) + execjs (~> 2.7) + less-rails (>= 3.0, < 5.0) + railties (>= 5.0, < 7.0) + +GIT + remote: https://github.com/twalpole/apparition.git + revision: ca86be4d54af835d531dbcd2b86e7b2c77f85f34 + ref: ca86be4 + specs: + apparition (0.6.0) + capybara (~> 3.13, < 4) + websocket-driver (>= 0.6.5) GEM remote: https://rubygems.org/ specs: - actioncable (5.2.5) - actionpack (= 5.2.5) + actioncable (6.1.4) + actionpack (= 6.1.4) + activesupport (= 6.1.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.5) - actionpack (= 5.2.5) - actionview (= 5.2.5) - activejob (= 5.2.5) + actionmailbox (6.1.4) + actionpack (= 6.1.4) + activejob (= 6.1.4) + activerecord (= 6.1.4) + activestorage (= 6.1.4) + activesupport (= 6.1.4) + mail (>= 2.7.1) + actionmailer (6.1.4) + actionpack (= 6.1.4) + actionview (= 6.1.4) + activejob (= 6.1.4) + activesupport (= 6.1.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.5) - actionview (= 5.2.5) - activesupport (= 5.2.5) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.4) + actionview (= 6.1.4) + activesupport (= 6.1.4) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.5) - activesupport (= 5.2.5) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.4) + actionpack (= 6.1.4) + activerecord (= 6.1.4) + activestorage (= 6.1.4) + activesupport (= 6.1.4) + nokogiri (>= 1.8.5) + actionview (6.1.4) + activesupport (= 6.1.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.5) - activesupport (= 5.2.5) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.4) + activesupport (= 6.1.4) globalid (>= 0.3.6) - activemodel (5.2.5) - activesupport (= 5.2.5) - activerecord (5.2.5) - activemodel (= 5.2.5) - activesupport (= 5.2.5) - arel (>= 9.0) - activestorage (5.2.5) - actionpack (= 5.2.5) - activerecord (= 5.2.5) + activemodel (6.1.4) + activesupport (= 6.1.4) + activerecord (6.1.4) + activemodel (= 6.1.4) + activesupport (= 6.1.4) + activestorage (6.1.4) + actionpack (= 6.1.4) + activejob (= 6.1.4) + activerecord (= 6.1.4) + activesupport (= 6.1.4) marcel (~> 1.0.0) - activesupport (5.2.5) + mini_mime (>= 1.1.0) + activesupport (6.1.4) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - addressable (2.7.0) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) airbrussh (1.4.0) sshkit (>= 1.6.1, != 1.7.0) - annotate (3.1.0) + annotate (3.1.1) activerecord (>= 3.2, < 7.0) rake (>= 10.4, < 14.0) - arel (9.0.0) - ast (2.4.1) - awesome_print (1.8.0) + ast (2.4.2) + awesome_print (1.9.2) barby (0.6.8) - better_errors (2.7.1) + bcrypt_pbkdf (1.1.0) + better_errors (2.9.1) coderay (>= 1.0.0) erubi (>= 1.0.0) rack (>= 0.9.0) @@ -87,33 +124,35 @@ GEM bootstrap-select-rails (1.13.8) browser (4.2.0) builder (3.2.4) - byebug (11.0.1) - capistrano (3.14.1) + byebug (11.1.3) + capistrano (3.16.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) sshkit (>= 1.9.0) capistrano-bundler (1.6.0) capistrano (~> 3.1) - capistrano-passenger (0.2.0) + capistrano-passenger (0.2.1) capistrano (~> 3.0) - capistrano-rails (1.5.0) + capistrano-rails (1.6.1) capistrano (~> 3.1) - capistrano-bundler (~> 1.1) - capistrano-rbenv (2.1.6) + capistrano-bundler (>= 1.1, < 3) + capistrano-rbenv (2.2.0) capistrano (~> 3.1) sshkit (~> 1.3) - capybara (3.15.1) + capybara (3.35.3) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) rack (>= 1.6.0) rack-test (>= 0.6.3) - regexp_parser (~> 1.2) + regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - chunky_png (1.3.11) + capybara-screenshot (1.0.25) + capybara (>= 1.0, < 4) + launchy + chunky_png (1.4.0) clipboard-rails (1.7.1) - cliver (0.3.2) coderay (1.1.3) coffee-rails (4.2.2) coffee-script (>= 2.2.0) @@ -123,91 +162,123 @@ GEM execjs coffee-script-source (1.12.2) commonjs (0.2.7) - concurrent-ruby (1.1.8) - coolline (0.5.0) - unicode_utils (~> 1.4) + concurrent-ruby (1.1.9) crass (1.0.6) data-confirm-modal (1.6.3) railties (>= 3.0) - database_cleaner (1.8.5) - debug_inspector (0.0.3) - diff-lcs (1.3) + database_cleaner (1.99.0) + debug_inspector (1.1.0) + diff-lcs (1.4.4) + dotenv (2.7.6) + dotenv-rails (2.7.6) + dotenv (= 2.7.6) + railties (>= 3.2) + ed25519 (1.2.4) erubi (1.10.0) - etc (1.1.0) - exception_notification (4.4.0) + exception_notification (4.4.3) actionmailer (>= 4.0, < 7) activesupport (>= 4.0, < 7) - execjs (2.7.0) - factory_girl (4.9.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.9.0) - factory_girl (~> 4.9.0) - railties (>= 3.0.0) - faraday (1.4.1) + execjs (2.8.1) + factory_bot (6.2.0) + activesupport (>= 5.0.0) + factory_bot_rails (6.2.0) + factory_bot (~> 6.2.0) + railties (>= 5.0.0) + faraday (1.7.0) + faraday-em_http (~> 1.0) + faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) + faraday-httpclient (~> 1.0.1) faraday-net_http (~> 1.0) faraday-net_http_persistent (~> 1.1) + faraday-patron (~> 1.0) + faraday-rack (~> 1.0) multipart-post (>= 1.2, < 3) ruby2_keywords (>= 0.0.4) + faraday-em_http (1.0.0) + faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) + faraday-httpclient (1.0.1) faraday-net_http (1.0.1) - faraday-net_http_persistent (1.1.0) - ffi (1.13.1) - font-awesome-rails (4.7.0.5) - railties (>= 3.2, < 6.1) - fuubar (2.5.0) + faraday-net_http_persistent (1.2.0) + faraday-patron (1.0.0) + faraday-rack (1.0.0) + ffi (1.15.3) + font-awesome-rails (4.7.0.7) + railties (>= 3.2, < 7) + formatador (0.3.0) + fuubar (2.5.1) rspec-core (~> 3.0) ruby-progressbar (~> 1.4) - globalid (0.4.2) - activesupport (>= 4.2.0) + globalid (0.5.2) + activesupport (>= 5.0) + guard (2.18.0) + formatador (>= 0.2.4) + listen (>= 2.7, < 4.0) + lumberjack (>= 1.0.12, < 2.0) + nenv (~> 0.1) + notiffany (~> 0.0) + pry (>= 0.13.0) + shellany (~> 0.0) + thor (>= 0.18.1) + guard-compat (1.2.1) + guard-rspec (4.7.3) + guard (~> 2.1) + guard-compat (~> 1.1) + rspec (>= 2.99.0, < 4.0) hashie (4.1.0) i18n (1.8.10) concurrent-ruby (~> 1.0) - i18n-js (3.7.0) + i18n-js (3.9.0) i18n (>= 0.6.6) - jbuilder (2.10.0) + jbuilder (2.11.2) activesupport (>= 5.0.0) jquery-rails (4.4.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - jwt (2.2.1) - launchy (2.4.3) - addressable (~> 2.3) + jwt (2.2.3) + launchy (2.5.0) + addressable (~> 2.7) less (2.6.0) commonjs (~> 0.2.7) - less-rails (2.8.0) - actionpack (>= 4.0) + less-rails (4.0.0) + actionpack (>= 4) less (~> 2.6.0) - sprockets (> 2, < 4) - tilt - listen (3.0.8) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) + sprockets (>= 2) + listen (3.6.0) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) lograge (0.11.2) actionpack (>= 4) activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.9.1) + loofah (2.12.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) + lumberjack (1.2.8) mail (2.7.1) mini_mime (>= 0.1.1) marcel (1.0.1) - method_source (0.9.2) + method_source (1.0.0) mini_mime (1.1.0) - mini_portile2 (2.4.0) + mini_portile2 (2.8.0) minitest (5.14.4) multipart-post (2.1.1) mysql2 (0.5.3) - net-ldap (0.16.2) + nenv (0.3.0) + net-ldap (0.17.0) net-scp (3.0.0) net-ssh (>= 2.6.5, < 7.0.0) net-ssh (6.1.0) - nio4r (2.5.7) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) + nio4r (2.5.8) + nokogiri (1.13.3) + mini_portile2 (~> 2.8.0) + racc (~> 1.4) + notiffany (0.1.3) + nenv (~> 0.1) + shellany (~> 0.0) omniauth (1.9.1) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) @@ -215,121 +286,149 @@ GEM omniauth (>= 1.0.0) omniauth-shibboleth-passive (0.1.0) omniauth-shibboleth (~> 1.1.0) - paper_trail (10.3.1) - activerecord (>= 4.2) + paper_trail (12.0.0) + activerecord (>= 5.2) request_store (~> 1.1) - parser (2.7.1.3) - ast (~> 2.4.0) - passenger (6.0.5) - etc + parallel (1.20.1) + parser (3.0.2.0) + ast (~> 2.4.1) + passenger (6.0.10) rack rake (>= 0.8.1) - poltergeist (1.18.1) - capybara (>= 2.1, < 4) - cliver (~> 0.3.1) - websocket-driver (>= 0.2.0) - powerpack (0.1.2) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - pry-byebug (3.7.0) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.9.0) byebug (~> 11.0) - pry (~> 0.10) - pry-coolline (0.2.5) - coolline (~> 0.5) + pry (~> 0.13.0) pry-rails (0.3.9) pry (>= 0.10.4) - public_suffix (4.0.5) - puma (3.12.6) - pundit (2.1.0) + public_suffix (4.0.6) + puma (4.3.8) + nio4r (~> 2.0) + pundit (2.1.1) activesupport (>= 3.0.0) + racc (1.6.0) rack (2.2.3) + rack-proxy (0.7.0) + rack rack-test (1.1.0) rack (>= 1.0, < 3) - rails (5.2.5) - actioncable (= 5.2.5) - actionmailer (= 5.2.5) - actionpack (= 5.2.5) - actionview (= 5.2.5) - activejob (= 5.2.5) - activemodel (= 5.2.5) - activerecord (= 5.2.5) - activestorage (= 5.2.5) - activesupport (= 5.2.5) - bundler (>= 1.3.0) - railties (= 5.2.5) + rack-utf8_sanitizer (1.7.0) + rack (>= 1.0, < 3.0) + rails (6.1.4) + actioncable (= 6.1.4) + actionmailbox (= 6.1.4) + actionmailer (= 6.1.4) + actionpack (= 6.1.4) + actiontext (= 6.1.4) + actionview (= 6.1.4) + activejob (= 6.1.4) + activemodel (= 6.1.4) + activerecord (= 6.1.4) + activestorage (= 6.1.4) + activesupport (= 6.1.4) + bundler (>= 1.15.0) + railties (= 6.1.4) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) + rails-html-sanitizer (1.4.1) loofah (~> 2.3) - railties (5.2.5) - actionpack (= 5.2.5) - activesupport (= 5.2.5) + railties (6.1.4) + actionpack (= 6.1.4) + activesupport (= 6.1.4) method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) - rainbow (2.2.2) - rake - rake (13.0.3) - rb-fsevent (0.10.4) + rake (>= 0.13) + thor (~> 1.0) + rainbow (3.0.0) + rake (13.0.6) + rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (1.7.1) + regexp_parser (2.1.1) request_store (1.5.0) rack (>= 1.4) - rqrcode (1.1.2) + rexml (3.2.5) + rqrcode (1.2.0) chunky_png (~> 1.0) - rqrcode_core (~> 0.1) - rqrcode_core (0.1.2) - rspec-core (3.9.2) - rspec-support (~> 3.9.3) - rspec-expectations (3.9.2) + rqrcode_core (~> 0.2) + rqrcode_core (0.2.0) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.1) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-mocks (3.9.1) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.2) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.9.0) - rspec-rails (4.0.1) + rspec-support (~> 3.10.0) + rspec-rails (4.1.2) actionpack (>= 4.2) activesupport (>= 4.2) railties (>= 4.2) - rspec-core (~> 3.9) - rspec-expectations (~> 3.9) - rspec-mocks (~> 3.9) - rspec-support (~> 3.9) - rspec-support (3.9.3) - rubocop (0.47.1) - parser (>= 2.3.3.1, < 3.0) - powerpack (~> 0.1) - rainbow (>= 1.99.1, < 3.0) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-retry (0.6.2) + rspec-core (> 3.3) + rspec-support (3.10.2) + rubocop (1.19.0) + parallel (~> 1.10) + parser (>= 3.0.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml + rubocop-ast (>= 1.9.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (~> 1.0, >= 1.0.1) - ruby-progressbar (1.10.1) - ruby2_keywords (0.0.4) + unicode-display_width (>= 1.4.0, < 3.0) + rubocop-ast (1.10.0) + parser (>= 3.0.1.1) + rubocop-performance (1.11.5) + rubocop (>= 1.7.0, < 2.0) + rubocop-ast (>= 0.4.0) + rubocop-rails (2.11.3) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.7.0, < 2.0) + rubocop-rake (0.6.0) + rubocop (~> 1.0) + rubocop-rspec (2.4.0) + rubocop (~> 1.0) + rubocop-ast (>= 1.1.0) + ruby-progressbar (1.11.0) + ruby2_keywords (0.0.5) sass (3.7.4) sass-listen (~> 4.0.0) sass-listen (4.0.0) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (5.0.7) - railties (>= 4.0.0, < 6) + sass-rails (5.1.0) + railties (>= 5.2.0) sass (~> 3.1) sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sentry-rails (4.4.0) + semantic_range (3.0.0) + sentry-rails (4.6.5) railties (>= 5.0) - sentry-ruby-core (~> 4.4.0.pre.beta) - sentry-ruby (4.4.2) + sentry-ruby-core (~> 4.6.0) + sentry-ruby (4.6.5) concurrent-ruby (~> 1.0, >= 1.0.2) faraday (>= 1.0) - sentry-ruby-core (= 4.4.2) - sentry-ruby-core (4.4.2) + sentry-ruby-core (= 4.6.5) + sentry-ruby-core (4.6.5) concurrent-ruby faraday - slack-notifier (2.3.2) + shellany (0.0.1) + shoulda-matchers (5.0.0) + activesupport (>= 5.2.0) + slack-notifier (2.4.0) sprockets (3.7.2) concurrent-ruby (~> 1.0) rack (> 1, < 3) @@ -338,103 +437,115 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) sqlite3 (1.4.2) - sshkit (1.21.0) + sshkit (1.21.2) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) thor (1.1.0) - thread_safe (0.3.6) tilt (2.0.10) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) - twitter-bootstrap-rails (4.0.0) - actionpack (~> 5.0, >= 5.0.1) - execjs (~> 2.7) - less-rails (~> 2.8, >= 2.8.0) - railties (~> 5.0, >= 5.0.1) - tzinfo (1.2.9) - thread_safe (~> 0.1) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - unicode-display_width (1.7.0) - unicode_utils (1.4.0) + unicode-display_width (2.0.0) web-console (3.7.0) actionview (>= 5.0) activemodel (>= 5.0) bindex (>= 0.4.0) railties (>= 5.0) - websocket-driver (0.7.3) + webpacker (5.4.0) + activesupport (>= 5.2) + rack-proxy (>= 0.6.1) + railties (>= 5.2) + semantic_range (>= 2.3.0) + websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) + zeitwerk (2.4.2) PLATFORMS ruby DEPENDENCIES - addressable + addressable (~> 2.8) ajax-datatables-rails! - annotate - awesome_print - barby - better_errors - binding_of_caller - bootstrap-select-rails - browser - byebug - capistrano - capistrano-bundler - capistrano-passenger (>= 0.1.1) - capistrano-rails - capistrano-rbenv - capybara - chunky_png - clipboard-rails - coffee-rails (~> 4.2.0) - data-confirm-modal - database_cleaner - exception_notification - factory_girl_rails - font-awesome-rails - fuubar - i18n-js - jbuilder (~> 2.0) - jquery-rails - jwt - launchy - listen (~> 3.0.5) - lograge - mysql2 - net-ldap - omniauth - omniauth-shibboleth - omniauth-shibboleth-passive - paper_trail - passenger - poltergeist - pry (= 0.12.2) - pry-byebug - pry-coolline - pry-rails - puma (~> 3.0) - pundit - rails (~> 5.2.0) - rqrcode - rspec-rails - rubocop (~> 0.47.1) + annotate (~> 3.1) + apparition! + awesome_print (~> 1.8) + barby (~> 0.6) + bcrypt_pbkdf (~> 1.1) + better_errors (~> 2.7) + binding_of_caller (~> 0.8) + bootstrap-select-rails (~> 1.13) + browser (~> 4.2) + byebug (~> 11.1) + capistrano (~> 3.14) + capistrano-bundler (~> 1.6) + capistrano-passenger (~> 0.2) + capistrano-rails (~> 1.5) + capistrano-rbenv (~> 2.1) + capybara (~> 3.15) + capybara-screenshot (~> 1.0) + chunky_png (~> 1.3) + clipboard-rails (~> 1.7) + coffee-rails (~> 4.2) + data-confirm-modal (~> 1.6) + database_cleaner (~> 1.8) + dotenv-rails (~> 2.7) + ed25519 (~> 1.2) + exception_notification (~> 4.4) + factory_bot_rails (~> 6.2) + font-awesome-rails (~> 4.7) + fuubar (~> 2.5) + guard (~> 2.17) + guard-rspec (~> 4.7) + i18n-js (~> 3.7) + jbuilder (~> 2.10) + jquery-rails (~> 4.4) + jwt (~> 2.2) + launchy (~> 2.4) + listen (~> 3.0) + lograge (~> 0.11) + mysql2 (~> 0.5) + net-ldap (~> 0.16) + omniauth (~> 1.9) + omniauth-shibboleth (~> 1.1) + omniauth-shibboleth-passive (~> 0.1) + paper_trail (~> 12.0) + passenger (~> 6.0) + pry (~> 0.13) + pry-byebug (~> 3.9) + pry-rails (~> 0.3) + puma (~> 4.3) + pundit (~> 2.1) + rack-utf8_sanitizer (~> 1.7) + rails (~> 6.1) + rqrcode (~> 1.1) + rspec-rails (~> 4.0) + rspec-retry (~> 0.6) + rubocop (~> 1.18) + rubocop-performance (~> 1.11) + rubocop-rails (~> 2.11) + rubocop-rake (~> 0.6.0) + rubocop-rspec (~> 2.4) sass-rails (~> 5.0) - sentry-rails - sentry-ruby - slack-notifier - sqlite3 + sentry-rails (~> 4.4) + sentry-ruby (~> 4.4) + shoulda-matchers (~> 5.0) + slack-notifier (~> 2.3) + sqlite3 (~> 1.4) starburst! - turbolinks (~> 5.x) - twitter-bootstrap-rails + turbolinks (~> 5.2) + twitter-bootstrap-rails! twitter-typeahead-rails! tzinfo-data - uglifier (>= 1.3.0) - web-console + uglifier (~> 4.2) + web-console (~> 3.7) + webpacker (~> 5.4) BUNDLED WITH - 2.2.16 + 2.2.20 diff --git a/Guardfile b/Guardfile new file mode 100644 index 00000000..84c87745 --- /dev/null +++ b/Guardfile @@ -0,0 +1,70 @@ +# A sample Guardfile +# More info at https://github.com/guard/guard#readme + +## Uncomment and set this to only include directories you want to watch +# directories %w(app lib config test spec features) \ +# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")} + +## Note: if you are using the `directories` clause above and you are not +## watching the project directory ('.'), then you will want to move +## the Guardfile to a watched dir and symlink it back, e.g. +# +# $ mkdir config +# $ mv Guardfile config/ +# $ ln -s config/Guardfile . +# +# and, you'll have to watch "config/Guardfile" instead of "Guardfile" + +# NOTE: The cmd option is now required due to the increasing number of ways +# rspec may be run, below are examples of the most common uses. +# * bundler: 'bundle exec rspec' +# * bundler binstubs: 'bin/rspec' +# * spring: 'bin/rspec' (This will use spring if running and you have +# installed the spring binstubs per the docs) +# * zeus: 'zeus rspec' (requires the server to be started separately) +# * 'just' rspec: 'rspec' + +guard :rspec, cmd: "bundle exec rspec" do + require "guard/rspec/dsl" + dsl = Guard::RSpec::Dsl.new(self) + + # Feel free to open issues for suggestions and improvements + + # RSpec files + rspec = dsl.rspec + watch(rspec.spec_helper) { rspec.spec_dir } + watch(rspec.spec_support) { rspec.spec_dir } + watch(rspec.spec_files) + + # Ruby files + ruby = dsl.ruby + dsl.watch_spec_files_for(ruby.lib_files) + + # Rails files + rails = dsl.rails(view_extensions: %w[erb haml slim]) + dsl.watch_spec_files_for(rails.app_files) + dsl.watch_spec_files_for(rails.views) + + watch(rails.controllers) do |m| + [ + rspec.spec.call("routing/#{m[1]}_routing"), + rspec.spec.call("controllers/#{m[1]}_controller"), + rspec.spec.call("acceptance/#{m[1]}") + ] + end + + # Rails config changes + watch(rails.spec_helper) { rspec.spec_dir } + watch(rails.routes) { "#{rspec.spec_dir}/routing" } + watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } + + # Capybara features specs + watch(rails.view_dirs) { |m| rspec.spec.call("features/#{m[1]}") } + watch(rails.layouts) { |m| rspec.spec.call("features/#{m[1]}") } + + # Turnip features and steps + watch(%r{^spec/acceptance/(.+)\.feature$}) + watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| + Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance" + end +end diff --git a/README.md b/README.md index df932ae8..3214896e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Z -Z is a custom URL shortener developed at LATIS@UMN. Instead of using a third party service, we use Z to create and manage University branded short links, for example: http://z.umn.edu/mycoolsite. The goal of this project is to provide a modern, open source solution to University branded short links. +[![tests](https://github.com/UMN-LATIS/z/actions/workflows/test.yml/badge.svg)](https://github.com/UMN-LATIS/z/actions/workflows/test.yml) + +Z is a custom URL shortener developed at LATIS@UMN. Instead of using a third party service, we use Z to create and manage University branded short links, for example: . The goal of this project is to provide a modern, open source solution to University branded short links. ## Features @@ -18,57 +20,89 @@ Z is a custom URL shortener developed at LATIS@UMN. Instead of using a third par ## Installation ([Docker](https://www.docker.com)) -The included `docker-composer.yml` and `Dockerfile` files should allow this application to be run in [Docker](https://www.docker.com). To get started, run +The included `docker-composer.yml` and `Dockerfile` files should allow this application to be run in [Docker](https://www.docker.com). + +Add a basic .env: - docker-compose run web rake db:create - docker-compose run web rails db:migrate RAILS_ENV=development +``` +DB_HOST=db +DB_PORT=3306 +DB_USERNAME=root +DB_PASSWORD=root +``` - To launch the application, run +To launch the application, run - docker-compose up + ```console + docker-compose up + ``` +To run the initial migrations, use: +```console + docker-compose run web rake db:create + docker-compose run web rails db:migrate RAILS_ENV=development + ``` - and connect to your localhost on port 3000. +then connect to your localhost on port 3000. ## Installation (Dockerless) + Make sure that config/database.yml is correctly configured with database credentials, and config/lda.yml is correctly configured with LDAP credentials, and an instance of MySQL is running. - rvm install 2.3.1 - gem install bundler - bundle install - rails db:reseed + ```console + rvm install 2.7.3 + gem install bundler + bundle install + rails db:reseed + ``` To launch the application, run - rails s + ```console + rails s + ``` - and connect to your localhost on port 3000. +and connect to your localhost on port 3000. ## Technology and Dependencies -- Rails 5.0.2 + +- Rails 6.1 - MySQL - LDAP (for directory lookup) ### Auth + - [OmniAuth](https://github.com/omniauth/omniauth), for authentication - [Pundit](https://github.com/elabs/pundit), for authorization ### Deployment + - [Capistrano](https://github.com/capistrano/capistrano), for deployment - Apache/[Passenger](https://github.com/phusion/passenger), as our server stack +- [LATIS Ansible Playbook](https://github.umn.edu/latis-sw/ansible_playbooks), for larger platform changes like a ruby version bump. + + ```console + bundle exec cap deploy + ``` + +#### Production Deployment + +Please see the [Deploying to Production](./deploy_to_production.md) page. ### Data After deploying, populate the ip2location_db1 table with the content from the [IP2Location LITE IP-Country Database](https://lite.ip2location.com/database/ip-country). ### Testing + - [Rspec](https://github.com/rspec/rspec)/[Capybara](https://github.com/teamcapybara/capybara), for testing -- [PhantomJS](http://phantomjs.org)/[Poltergeist](https://github.com/teampoltergeist/poltergeist), for browser emulation +- [PhantomJS](http://phantomjs.org)/[Apparition](https://github.com/twalpole/apparition), for browser emulation -The application has a a comprehensive testing suite using Rspec and Capybara. Front end tests are configured to run with PhantomJS and Poltergeist. The test suite can be ran by running: +The application has a a comprehensive testing suite using Rspec and Capybara. Front end tests are configured to run with PhantomJS and Apparition. The test suite can be ran by running: - rspec + bundle exec rspec ### Other tech + - [Paper trail](https://github.com/airblade/paper_trail), for URL version history - [Turbolinks](https://github.com/turbolinks/turbolinks), for faster browsing - [Typeahead](https://github.com/twitter/typeahead.js/), for user autocomplete @@ -78,12 +112,13 @@ The application has a a comprehensive testing suite using Rspec and Capybara. Fr - [Starburst](https://github.com/csm123/starburst), for in-app announcements ## Customization + Z was designed to be forkable and customizable. Most of the language has been extracted into a [single localization file](https://github.umn.edu/latis-sw/z/blob/develop/config/locales/en.bootstrap.yml). This allows you to change any language and make Z applicable to your environment. Z uses [OmniAuth](https://github.com/omniauth/omniauth), which supports a wide variety of [authentication strategies](https://github.com/omniauth/omniauth/wiki/list-of-strategies). ## Contribute -- Issue Tracker: https://github.umn.edu/latis-sw/z/issues -- Source Code: https://github.umn.edu/latis-sw/z +- Issue Tracker: +- Source Code: ## Support diff --git a/app/assets/images/goldy-in-a-hole.png b/app/assets/images/goldy-in-a-hole.png new file mode 100644 index 00000000..5406b77c Binary files /dev/null and b/app/assets/images/goldy-in-a-hole.png differ diff --git a/app/assets/images/goldy-in-a-hole.svg b/app/assets/images/goldy-in-a-hole.svg new file mode 100644 index 00000000..dc76de3d --- /dev/null +++ b/app/assets/images/goldy-in-a-hole.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/javascripts/group_members.js b/app/assets/javascripts/group_members.js index 2da5848e..d2ffc113 100644 --- a/app/assets/javascripts/group_members.js +++ b/app/assets/javascripts/group_members.js @@ -10,3 +10,29 @@ $(document).bind('turbolinks:load', function () { } ] }); }); + +// new member form submit button disabled unless +// all required fields have some value +$(() => { + const newMemberForm = document.querySelector("form.new_member"); + if (!newMemberForm) return; + + function handleNewMemberFormChange() { + const requiredInputs = document.querySelectorAll( + ".new_member input[required]" + ); + const submitButton = document.querySelector('button[type="submit"]'); + + const hasValue = (input) => !!input.value.length; + const isComplete = (inputEls) => [...inputEls].every(hasValue); + + submitButton.disabled = !isComplete(requiredInputs); + } + + ["keyup", "change", "paste"].forEach((eventType) => + newMemberForm.addEventListener(eventType, handleNewMemberFormChange) + ); + + // init submit button on page load + handleNewMemberFormChange(); +}); diff --git a/app/assets/stylesheets/2015-tc.css.scss b/app/assets/stylesheets/2015-tc.css.scss index 64684650..ab24f31f 100644 --- a/app/assets/stylesheets/2015-tc.css.scss +++ b/app/assets/stylesheets/2015-tc.css.scss @@ -46,7 +46,7 @@ body { margin: 0; } .mobile input[type="text"] { -webkit-appearance: none; -moz-border-radius: 0; border-radius: 0; } -#umnhf-h-st { position: absolute; right: 30px; width: 175px; height: 22px; padding-left: 3px; cursor: text; color: #8a8a8a; border: 0; background-color: #fff; font-size: 0.77778rem; line-height: 18px; -webkit-appearance: none; -moz-border-radius: 0; border-radius: 0; } +#umnhf-h-st { position: absolute; right: 30px; width: 175px; height: 22px; padding-left: 3px; cursor: text; color: #333; border: 0; background-color: #fff; font-size: 0.77778rem; line-height: 18px; -webkit-appearance: none; -moz-border-radius: 0; border-radius: 0; } #umnhf-h-sb { position: absolute; top: 0; right: 0; overflow: hidden; width: 22px; height: 22px; cursor: pointer; white-space: nowrap; color: #7a0019; border: 0; font: bold 0.925em/1.35em arial,helvetica,clean,sans-serif; background: transparent asset-url("sprites/lock-search-wht.png") 0 -12px no-repeat; } @media only screen and (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 192dpi) { #umnhf-h-sb { background: transparent asset-url("sprites/lock-search-wht.png") 0 -12px no-repeat; background-size: 22px 34px; } } diff --git a/app/assets/stylesheets/_error-page.scss b/app/assets/stylesheets/_error-page.scss new file mode 100644 index 00000000..d25db65a --- /dev/null +++ b/app/assets/stylesheets/_error-page.scss @@ -0,0 +1,52 @@ +.error-page { + --black: #000; + --maroon: #7a0019; + color: var(--black); + line-height: 1.4; +} + +.error-page a { + color: var(--maroon); +} + +.error-page p { + font-size: inherit; + line-height: inherit; +} + +.error-page__image { + display: block; + margin: 1rem auto 3rem; + width: 50%; + min-width: 12rem; + max-width: 30rem; +} + +.error-page__heading { + font-size: 6rem; + margin-top: 4rem; + margin-bottom: 1rem; +} + +.error-page__subheading { + font-size: 3rem; + margin-top: 0; +} + +.error-page__message { + font-size: 1.25rem; + max-width: 30rem; + margin: auto; +} + +@media (max-width: 32rem) { + .error-page__heading { + font-size: 4rem; + } + .error-page__subheading { + font-size: 2rem; + } + .error-page__message { + font-size: 1rem; + } +} diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index d7a93464..c2627a83 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -11,6 +11,7 @@ * It is generally better to create a new file per style scope. * *= require_self + *= require bootstrap_and_overrides *= require_tree *= require bootstrap-select */ diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css b/app/assets/stylesheets/bootstrap_and_overrides.css new file mode 100644 index 00000000..5b887c7b --- /dev/null +++ b/app/assets/stylesheets/bootstrap_and_overrides.css @@ -0,0 +1,6 @@ +/* + =require twitter-bootstrap-static/bootstrap + + Static version of css will use Glyphicons sprites by default + =require twitter-bootstrap-static/sprites +*/ \ No newline at end of file diff --git a/app/assets/stylesheets/errors.scss b/app/assets/stylesheets/errors.scss index 5b23d977..2e7c8584 100644 --- a/app/assets/stylesheets/errors.scss +++ b/app/assets/stylesheets/errors.scss @@ -1,3 +1,5 @@ // Place all the styles related to the errors controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ + +@import "error-page"; diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index d86c54b5..dbfd327c 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -727,3 +727,7 @@ $loader-color: $primaryColor; .loading-indicator{ @include loader01; } + +img { + max-width: 100%; +} \ No newline at end of file diff --git a/app/controllers/admin/admins_controller.rb b/app/controllers/admin/admins_controller.rb index bac54871..6faba7b9 100644 --- a/app/controllers/admin/admins_controller.rb +++ b/app/controllers/admin/admins_controller.rb @@ -1,15 +1,15 @@ class Admin::AdminsController < ApplicationController - before_action :set_admin_view + before_action :set_admin_view - def index - #code - end + def index + # code + end - def create - #code - end + def create + # code + end - def destroy - #code - end + def destroy + # code + end end diff --git a/app/controllers/admin/announcements_controller.rb b/app/controllers/admin/announcements_controller.rb index e7f5c072..78a5cca0 100644 --- a/app/controllers/admin/announcements_controller.rb +++ b/app/controllers/admin/announcements_controller.rb @@ -1,21 +1,19 @@ class Admin::AnnouncementsController < ApplicationController - before_action :set_admin_announcement, only: [:show, :edit, :update, :destroy] + before_action :set_admin_announcement, only: %i[show edit update destroy] before_action :ensure_signed_in before_action :set_admin_view before_action :ensure_is_admin - # GET /admin/announcements # GET /admin/announcements.json def index @admin_announcements = Admin::Announcement.all - authorize @admin_announcements unless @admin_announcements .nil? + authorize @admin_announcements unless @admin_announcements.nil? end # GET /admin/announcements/1 # GET /admin/announcements/1.json - def show - end + def show; end # GET /admin/announcements/new def new @@ -23,8 +21,7 @@ def new end # GET /admin/announcements/1/edit - def edit - end + def edit; end # POST /admin/announcements # POST /admin/announcements.json @@ -33,9 +30,9 @@ def create respond_to do |format| if @admin_announcement.save - format.html {redirect_to admin_announcements_url, notice: 'Announcement was successfully created.'} + format.html { redirect_to admin_announcements_url, notice: 'Announcement was successfully created.' } else - format.html {render :new} + format.html { render :new } end end end @@ -45,9 +42,9 @@ def create def update respond_to do |format| if @admin_announcement.update(admin_announcement_params) - format.html {redirect_to admin_announcements_url, notice: 'Announcement was successfully updated.'} + format.html { redirect_to admin_announcements_url, notice: 'Announcement was successfully updated.' } else - format.html {render :edit} + format.html { render :edit } end end end @@ -57,18 +54,19 @@ def update def destroy @admin_announcement.destroy respond_to do |format| - format.html {redirect_to admin_announcements_url, notice: 'Announcement was successfully destroyed.'} - format.json {head :no_content} + format.html { redirect_to admin_announcements_url, notice: 'Announcement was successfully destroyed.' } + format.json { head :no_content } end end private + # Use callbacks to share common setup or constraints between actions. def set_admin_announcement @admin_announcement = Admin::Announcement.find(params[:id]) end - # Never trust parameters from the scary internet, only allow the white list through. + # Never trust parameters from the scary internet, only allow the allowlist through. def admin_announcement_params params.require(:admin_announcement).permit(:title, :body, :start_delivering_at, :stop_delivering_at) end diff --git a/app/controllers/admin/audits_controller.rb b/app/controllers/admin/audits_controller.rb index bbb68289..66022ee3 100644 --- a/app/controllers/admin/audits_controller.rb +++ b/app/controllers/admin/audits_controller.rb @@ -9,5 +9,4 @@ def index @audits = Audit.first authorize @audits unless @audits.nil? end - -end \ No newline at end of file +end diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index 856cd6dc..0400f763 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -6,5 +6,4 @@ class Admin::GroupsController < ApplicationController def index @groups = Group.not_default end - end diff --git a/app/controllers/admin/members_controller.rb b/app/controllers/admin/members_controller.rb index ce9c42b1..cc8ee1fd 100644 --- a/app/controllers/admin/members_controller.rb +++ b/app/controllers/admin/members_controller.rb @@ -2,7 +2,6 @@ class Admin::MembersController < ApplicationController before_action :ensure_signed_in before_action :ensure_is_admin - def index @admins = User.where(admin: true) authorize :admin_membership @@ -18,12 +17,14 @@ def new def create authorize :admin_membership member = User.where(uid: params[:uid]).first - member = User.create(user_params) unless member + member ||= User.create(user_params) member.admin = true member.save respond_to do |format| if member.admin? + # rubocop: disable Rails/RenderInline format.js { render inline: "location.reload();" } + # rubocop: enable Rails/RenderInline else format.html { render :new } format.json { render json: member.errors, status: :unprocessable_entity } @@ -32,7 +33,6 @@ def create end end - def destroy @member = User.find(params[:id]) authorize :admin_membership @@ -44,12 +44,17 @@ def destroy # current user is redirect to signin page if they remove their own admin status, # resigning the current user in allows the redirect to urls work properly sign_in current_user - format.html { redirect_to shortener_url, notice: 'Admin Membership: You have successfully removed your administrative privileges and have been routed back to your home page.' } + format.html do + redirect_to shortener_url, + notice: 'Admin Membership: You have successfully removed your administrative privileges and have been routed back to your home page.' + end else - format.html { redirect_to admin_members_url, notice: "Admin Membership: #{@member.display_name} (#{@member.internet_id}) has been removed." } + format.html do + redirect_to admin_members_url, + notice: "Admin Membership: #{@member.display_name} (#{@member.internet_id}) has been removed." + end end end - end private @@ -57,5 +62,4 @@ def destroy def user_params params.permit(:uid) end - end diff --git a/app/controllers/admin/transfer_requests_controller.rb b/app/controllers/admin/transfer_requests_controller.rb index 134aaa48..62728ba3 100644 --- a/app/controllers/admin/transfer_requests_controller.rb +++ b/app/controllers/admin/transfer_requests_controller.rb @@ -30,7 +30,7 @@ def create @transfer_request.urls = @urls respond_to do |format| - if @transfer_request.save + if @transfer_request.save format.js do redirect_to admin_urls_path end diff --git a/app/controllers/admin/url_csvs_controller.rb b/app/controllers/admin/url_csvs_controller.rb index 6617ca4e..b3be14ff 100644 --- a/app/controllers/admin/url_csvs_controller.rb +++ b/app/controllers/admin/url_csvs_controller.rb @@ -1,16 +1,16 @@ # controllers/url_csvs_controller.rb class Admin::UrlCsvsController < ApplicationController def show - @duration = params[:duration] - @time_unit = params[:time_unit] - @urls = Url.all + @duration = params[:duration] + @time_unit = params[:time_unit] + @urls = Url.all - # Sneaky bad guy figures out url of target website and wants the good stuff - # logs in only to find he is not in the group to which this url(s) belong? - authorize @urls, :csvs? unless @urls.nil? + # Sneaky bad guy figures out url of target website and wants the good stuff + # logs in only to find he is not in the group to which this url(s) belong? + authorize @urls, :csvs? unless @urls.nil? - respond_to do |format| - format.csv { send_data Url.to_csv(@duration, @time_unit, @urls) } - end + respond_to do |format| + format.csv { send_data Url.to_csv(@duration, @time_unit, @urls) } + end end end diff --git a/app/controllers/admin/urls_controller.rb b/app/controllers/admin/urls_controller.rb index 3b36b6e7..51be542c 100644 --- a/app/controllers/admin/urls_controller.rb +++ b/app/controllers/admin/urls_controller.rb @@ -1,5 +1,5 @@ class Admin::UrlsController < ApplicationController - before_action :set_url, only: [:show, :edit, :update, :destroy] + before_action :set_url, only: %i[show edit update destroy] before_action :ensure_signed_in before_action :set_admin_view @@ -8,9 +8,7 @@ def index @urls = Url.by_keyword(params[:url_filter_keyword]) authorize @urls unless @urls.nil? # If owner filter present, filter further - if params[:url_filter_owner].present? - @urls = @urls.created_by_name('params[:url_filter_owner]') - end + @urls = @urls.created_by_name('params[:url_filter_owner]') if params[:url_filter_owner].present? end # GET /urls/1 @@ -65,7 +63,7 @@ def set_url end # Never trust parameters from the scary internet - # only allow the white list through. + # only allow the allowlist through. def url_params params.require(:url).permit(:url, :keyword, :group_id, :modified_by, :duration, :time_unit) end diff --git a/app/controllers/api/v1/urls_controller.rb b/app/controllers/api/v1/urls_controller.rb index c16cb9f6..05be2021 100644 --- a/app/controllers/api/v1/urls_controller.rb +++ b/app/controllers/api/v1/urls_controller.rb @@ -26,5 +26,4 @@ def create render json: urls end - end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0f241aa4..c379174c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,6 +5,8 @@ class ApplicationController < ActionController::Base include SessionsHelper include Pundit rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized + rescue_from ActiveRecord::RecordNotFound, with: :render_not_found + rescue_from ActionController::BadRequest, with: :render_not_found helper Starburst::AnnouncementsHelper @@ -38,6 +40,10 @@ def set_admin_view @admin_view = true end + def render_not_found + render template: 'errors/not_found', layout: 'layouts/application', status: :not_found, formats: [:html] + end + private def user_not_authorized diff --git a/app/controllers/batch_delete_controller.rb b/app/controllers/batch_delete_controller.rb index fb15806f..97291ad6 100644 --- a/app/controllers/batch_delete_controller.rb +++ b/app/controllers/batch_delete_controller.rb @@ -15,15 +15,15 @@ def create format.js do redirect_to urls_path end - # - # respond_to do |format| - # if - # format.js do - # redirect_to urls_path - # end - # else - # format.js { render 'batch_delete/new', layout: false } - # end + # + # respond_to do |format| + # if + # format.js do + # redirect_to urls_path + # end + # else + # format.js { render 'batch_delete/new', layout: false } + # end end end end diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb index 0aae4f16..d35d9ade 100644 --- a/app/controllers/errors_controller.rb +++ b/app/controllers/errors_controller.rb @@ -1,8 +1,9 @@ class ErrorsController < ApplicationController - def not_found - render status: 404, :formats => [:html] + def not_found + render status: :not_found, formats: [:html] end + def internal_server_error - render status: 500 + render status: :internal_server_error end end diff --git a/app/controllers/faq_controller.rb b/app/controllers/faq_controller.rb index a334c397..17c7d998 100644 --- a/app/controllers/faq_controller.rb +++ b/app/controllers/faq_controller.rb @@ -1,5 +1,5 @@ class FaqController < ApplicationController - def index - @faqs = FrequentlyAskedQuestion.all - end + def index + @faqs = FrequentlyAskedQuestion.all + end end diff --git a/app/controllers/group_memberships_controller.rb b/app/controllers/group_memberships_controller.rb index 0ea5bf2a..19f24674 100644 --- a/app/controllers/group_memberships_controller.rb +++ b/app/controllers/group_memberships_controller.rb @@ -1,10 +1,8 @@ class GroupMembershipsController < ApplicationController - before_action :set_params, only: [:show, :index, :update, :create, :destroy] + before_action :set_params, only: %i[show index update create destroy] before_action :ensure_signed_in - - def index - end + def index; end def new render json: UserLookup.new( @@ -20,7 +18,9 @@ def create @group.add_user(member) respond_to do |format| if @group.user?(member) + # rubocop: disable Rails/RenderInline format.js { render inline: "location.reload();" } + # rubocop: enable Rails/RenderInline else format.html { render :new } format.json { render json: @group.errors, status: :unprocessable_entity } @@ -29,16 +29,14 @@ def create end end - def destroy @member = User.find(params[:id]) @group.remove_user(@member) respond_to do |format| format.html { redirect_to groups_url, notice: 'Group was successfully updated, user removed.' } format.json { head :no_content } - format.js { render :layout => false } + format.js { render layout: false } end - end private @@ -53,5 +51,4 @@ def set_params def user_params params.permit(:uid) end - end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index eb484a03..3b9de41d 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -1,6 +1,6 @@ # controllers/groups_controller.rb class GroupsController < ApplicationController - before_action :set_group, only: [:show, :edit, :update, :destroy] + before_action :set_group, only: %i[show edit update destroy] before_action :ensure_signed_in def index @@ -21,11 +21,9 @@ def show def new @group = Group.new - @group_identifier = Time.now.to_ms + @group_identifier = Time.zone.now.to_ms - if params[:keyword] - @url = Url.find_by(keyword: params[:keyword]) - end + @url = Url.find_by(keyword: params[:keyword]) if params[:keyword] respond_to do |format| format.js { render layout: false } end @@ -36,9 +34,7 @@ def create @group = Group.new(group_params) @group.users << current_user - if params[:keyword] - @group.urls << Url.find_by(keyword: params[:keyword]) - end + @group.urls << Url.find_by(keyword: params[:keyword]) if params[:keyword] respond_to do |format| if @group.save @@ -47,7 +43,7 @@ def create sign_in current_user format.js { render :create } elsif params[:modal] - format.js { render "groups/new", layout: false} + format.js { render "groups/new", layout: false } else format.js { render :edit } end @@ -97,7 +93,7 @@ def set_group @group_identifier = @group.id end - # Never trust parameters from the scary internet, only allow the white list + # Never trust parameters from the scary internet, only permit the allowlist # through. def group_params params.require(:group).permit(:name, :description) diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index c7d5e326..d45bac84 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,12 +1,5 @@ class HomeController < ApplicationController before_action :redirect_to_urls_if_logged_in - force_ssl if: :ssl_configured? - def index - - end - - def ssl_configured? - !Rails.env.development? - end + def index; end end diff --git a/app/controllers/move_to_group_controller.rb b/app/controllers/move_to_group_controller.rb index 421917e0..830b581c 100644 --- a/app/controllers/move_to_group_controller.rb +++ b/app/controllers/move_to_group_controller.rb @@ -1,4 +1,7 @@ class MoveToGroupController < ApplicationController + before_action :ensure_signed_in + rescue_from "ActionController::UnknownFormat", with: :render_not_found + def new @urls = Url .where(keyword: params[:keywords]) @@ -6,7 +9,6 @@ def new @groups = current_user.groups respond_to do |format| - format.html format.js { render 'move_to_group/new', layout: false } end end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 5552a384..9e9049e8 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -8,8 +8,8 @@ def show end private + def valid_page? File.exist?(Pathname.new(Rails.root + "app/views/pages/#{params[:page]}.html.erb")) end - -end \ No newline at end of file +end diff --git a/app/controllers/redirect_controller.rb b/app/controllers/redirect_controller.rb index 8bc9131d..d1715bdb 100644 --- a/app/controllers/redirect_controller.rb +++ b/app/controllers/redirect_controller.rb @@ -1,4 +1,5 @@ -class RedirectController < ActionController::Base +# class RedirectController < ActionController::Base +class RedirectController < ApplicationController def index url = Url.find_by(keyword: params[:keyword]) @@ -7,9 +8,7 @@ def index else redirect_to(url.url) browser = Browser.new(request.user_agent, accept_language: "en-us") - if(!browser.bot?) - url.add_click!(request.remote_ip) - end + url.add_click!(request.remote_ip) unless browser.bot? end end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 69a75151..6fd769bf 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,3 +1,7 @@ +def is_dev_or_test_env? + Rails.env.development? || Rails.env.test? +end + class SessionsController < ApplicationController skip_before_action :verify_authenticity_token @@ -8,7 +12,7 @@ def new def create # Filter out isGuest shibboleth requests. This is almost surely the wrong way to filter logins with # omniAuth. TODO: refactor. - if !Rails.env.development? && auth_hash["extra"]["raw_info"]["isGuest"] == "Y" + if !is_dev_or_test_env? && auth_hash["extra"]["raw_info"]["isGuest"] == "Y" redirect_to root_path return end @@ -23,7 +27,7 @@ def create def destroy sign_out - if Rails.env.development? + if is_dev_or_test_env? redirect_to root_path else redirect_to shib_logout_url @@ -35,5 +39,4 @@ def destroy def auth_hash request.env['omniauth.auth'] end - end diff --git a/app/controllers/transfer_requests_controller.rb b/app/controllers/transfer_requests_controller.rb index 821177d5..59d27c8c 100644 --- a/app/controllers/transfer_requests_controller.rb +++ b/app/controllers/transfer_requests_controller.rb @@ -1,6 +1,6 @@ class TransferRequestsController < ApplicationController before_action :set_transfer_request, - only: [:edit, :update, :destroy, :show, :confirm] + only: %i[edit update destroy show confirm] def index @transfer_requests_to = TransferRequest.where(to_group_id: current_user.id) diff --git a/app/controllers/url_csvs_controller.rb b/app/controllers/url_csvs_controller.rb index 3a2d56a2..ca3aeec9 100644 --- a/app/controllers/url_csvs_controller.rb +++ b/app/controllers/url_csvs_controller.rb @@ -3,12 +3,11 @@ class UrlCsvsController < ApplicationController def show_aggregated @duration = params[:duration] @time_unit = params[:time_unit] - if params[:url_id].present? - @urls = [Url.find(params[:url_id])] - else - @urls = - Url.created_by_id(current_user.context_group_id).not_in_pending_transfer_request - end + @urls = if params[:url_id].present? + [Url.find(params[:url_id])] + else + Url.created_by_id(current_user.context_group_id).not_in_pending_transfer_request + end # Sneaky bad guy figures out url of target website and wants the good stuff # logs in only to find he is not in the group to which this url(s) belong? @@ -26,5 +25,4 @@ def show format.csv { send_data url.click_data_to_csv } end end - end diff --git a/app/controllers/urls_controller.rb b/app/controllers/urls_controller.rb index 511d0c3a..116c280d 100644 --- a/app/controllers/urls_controller.rb +++ b/app/controllers/urls_controller.rb @@ -1,13 +1,12 @@ # controllers/url_controller.rb class UrlsController < ApplicationController - before_action :set_url, only: [:edit, :update, :destroy] + before_action :set_url, only: %i[edit update destroy] before_action :set_url_friendly, only: [:show] before_action :ensure_signed_in # GET /urls # GET /urls.json def index - @group = Group.find(current_user.context_group_id) @urls = @@ -71,7 +70,7 @@ def edit # GET /urls/new def new @url = Url.new - @url_identifier = Time.now.to_ms + @url_identifier = Time.zone.now.to_ms respond_to do |format| format.js { render layout: false } end @@ -136,18 +135,22 @@ def keyword_filter # Use callbacks to share common setup or constraints between actions. def set_url @url = Url.find(params[:id]) + raise ActiveRecord::RecordNotFound if @url.nil? + authorize @url unless @url.nil? @url_identifier = @url.id end def set_url_friendly @url = Url.find_by(keyword: params[:id]) + raise ActiveRecord::RecordNotFound if @url.nil? + authorize @url unless @url.nil? @url_identifier = @url.id end # Never trust parameters from the scary internet, - # only allow the white list through. + # only permit the allowlist through. def url_params params.require(:url).permit(:url, :keyword, :group_id, :modified_by) end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e0ba76e8..73a76fe3 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,5 +1,5 @@ class UsersController < ApplicationController def show - #code - end + # code + end end diff --git a/app/datatables/admin_url_datatable.rb b/app/datatables/admin_url_datatable.rb index c6c03ddb..6f075637 100644 --- a/app/datatables/admin_url_datatable.rb +++ b/app/datatables/admin_url_datatable.rb @@ -1,5 +1,6 @@ class AdminUrlDatatable < AjaxDatatablesRails::Base - def_delegators :@view, :link_to, :full_url, :display_long_url, :display_keyword_url, :select_tag, :options_from_collection_for_select, :url_path, :render + def_delegators :@view, :link_to, :full_url, :display_long_url, :display_keyword_url, :select_tag, + :options_from_collection_for_select, :url_path, :render def view_columns @view_columns ||= { @@ -21,8 +22,8 @@ def data # example: record.attribute, group_id: record.group_id, group_name: record.group.name, - url: link_to(display_long_url(record.url), record.url, target: '_blank'), - keyword: link_to(display_keyword_url(record.keyword), full_url(record), target: '_blank'), + url: link_to(display_long_url(record.url), record.url, target: '_blank', rel: 'noopener'), + keyword: link_to(display_keyword_url(record.keyword), full_url(record), target: '_blank', rel: 'noopener'), total_clicks: record.total_clicks, created_at: record.created_at.to_s(:created_on_formatted), actions: render( @@ -30,7 +31,7 @@ def data partial: 'urls/in_row_actions', locals: { url: record, admin_view: true } ), - 'DT_RowData_keyword' => record.keyword , + 'DT_RowData_keyword' => record.keyword, 'DT_RowData_url' => record.url, 'DT_RowId' => "url-#{record.id}" } diff --git a/app/datatables/audit_datatable.rb b/app/datatables/audit_datatable.rb index 7cb65f49..f3cbbad0 100644 --- a/app/datatables/audit_datatable.rb +++ b/app/datatables/audit_datatable.rb @@ -3,13 +3,14 @@ class AuditDatatable < AjaxDatatablesRails::Base def view_columns @view_columns ||= { - item_type: { source: 'Audit.item_type' }, - event: { source: 'Audit.event' }, - whodunnit: { source: 'Audit.whodunnit' }, - audit_history: { source: 'Audit.version_history' }, - created_at: { source: 'Audit.created_at' } + item_type: { source: 'Audit.item_type' }, + event: { source: 'Audit.event' }, + whodunnit: { source: 'Audit.whodunnit' }, + audit_history: { source: 'Audit.version_history' }, + created_at: { source: 'Audit.created_at' } } end + private def data @@ -17,20 +18,21 @@ def data posi = [] records.each do |record| next if visited.include? "#{record.item_id}-#{record.item_type}" + visited << "#{record.item_id}-#{record.item_type}" posi << record end records = posi records.map do |record| { - # comma separated list of the values for each cell of a table row - # example: record.attribute, - item_type: record.item_type, - event: record.event, - whodunnit: display_whodunnit_internet_id(record), - audit_history: record.version_history, - created_at: record.created_at.to_s(:created_on_formatted), - 'DT_RowId' => "audit-#{record.id}" + # comma separated list of the values for each cell of a table row + # example: record.attribute, + item_type: record.item_type, + event: record.event, + whodunnit: display_whodunnit_internet_id(record), + audit_history: record.version_history, + created_at: record.created_at.to_s(:created_on_formatted), + 'DT_RowId' => "audit-#{record.id}" } end end @@ -38,6 +40,6 @@ def data def get_raw_records Audit.order(created_at: :desc) end -# max(created_at) -# ==== Insert 'presenter'-like methods below if necessary + # max(created_at) + # ==== Insert 'presenter'-like methods below if necessary end diff --git a/app/datatables/url_datatable.rb b/app/datatables/url_datatable.rb index b3d82fce..ee98dbd1 100644 --- a/app/datatables/url_datatable.rb +++ b/app/datatables/url_datatable.rb @@ -1,5 +1,6 @@ class UrlDatatable < AjaxDatatablesRails::Base - def_delegators :@view, :link_to, :full_url, :display_long_url, :display_keyword_url, :select_tag, :options_for_select, :url_path, :render, :display_name, :group_names_and_ids_for_select + def_delegators :@view, :link_to, :full_url, :display_long_url, :display_keyword_url, :select_tag, + :options_for_select, :url_path, :render, :display_name, :group_names_and_ids_for_select def view_columns @view_columns ||= { @@ -35,20 +36,20 @@ def data group_id: record.group_id } ), - url: link_to(display_long_url(record.url), record.url, target: '_blank'), + url: link_to(display_long_url(record.url), record.url, target: '_blank', rel: 'noopener'), keyword: render( - formats: [:html], - partial: 'urls/short_url_table_cell', - locals: { url: record} + formats: [:html], + partial: 'urls/short_url_table_cell', + locals: { url: record } ), - total_clicks: link_to(record.total_clicks, url_path(record.keyword), target: '_blank'), + total_clicks: link_to(record.total_clicks, url_path(record.keyword), target: '_blank', rel: 'noopener'), created_at: record.created_at.to_s(:created_on_formatted), actions: render( formats: [:html], partial: 'urls/in_row_actions', locals: { url: record, admin_view: false } ), - 'DT_RowData_keyword' => record.keyword , + 'DT_RowData_keyword' => record.keyword, 'DT_RowData_url' => record.url, 'DT_RowId' => "url-#{record.id}" } diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c2373e48..0f223366 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,23 +1,23 @@ module ApplicationHelper - - # Return true if a user is logged in through shibboleth. + # Return true if a user is logged in through shibboleth. def logged_in? -# if current_agent.blank? or current_agent.internet_id == "anonymous" -# false -# else -# true -# end -false + # if current_agent.blank? or current_agent.internet_id == "anonymous" + # false + # else + # true + # end + false end - def bootstrap_class_for flash_type - { success: "alert-success", error: "alert-danger", alert: "alert-warning", notice: "alert-info" }[flash_type.to_sym] || flash_type.to_s + def bootstrap_class_for(flash_type) + { success: "alert-success", error: "alert-danger", alert: "alert-warning", + notice: "alert-info" }[flash_type.to_sym] || flash_type.to_s end - def flash_messages(opts = {}) + def flash_messages(_opts = {}) flash.each do |msg_type, message| - concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do - concat content_tag(:button, 'x', class: "close", data: { dismiss: 'alert' }) + concat(tag.div(message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do + concat tag.button('x', class: "close", data: { dismiss: 'alert' }) concat message end) end diff --git a/app/helpers/clicks_helper.rb b/app/helpers/clicks_helper.rb index 3fbf7db7..f43bfd0c 100644 --- a/app/helpers/clicks_helper.rb +++ b/app/helpers/clicks_helper.rb @@ -31,6 +31,6 @@ def click_data_formatter(clicks) end def region_data_formatter(clicks) - clicks.dup.unshift %w(Country Clicks) + clicks.dup.unshift %w[Country Clicks] end end diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index ff8b5211..242a7e2d 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -1,25 +1,25 @@ module FormHelper def form_for_url_admin(admin_view, url, &block) - if admin_view - form_for [:admin, url], html: { class: 'form-inline url', remote: true }, &block - else - form_for url, html: { class: 'form-inline url', remote: true }, &block - end + if admin_view + form_for [:admin, url], html: { class: 'form-inline url', remote: true }, &block + else + form_for url, html: { class: 'form-inline url', remote: true }, &block + end end def form_for_transfer_admin(admin_view, transfer_request, &block) - if admin_view - form_for [:admin, transfer_request], html: { remote: true }, &block - else - form_for transfer_request, html: { remote: true }, &block - end + if admin_view + form_for [:admin, transfer_request], html: { remote: true }, &block + else + form_for transfer_request, html: { remote: true }, &block + end end def form_for_group_admin(admin_view, group, &block) - if admin_view - form_for [:admin, group], html: { remote: true }, &block - else - form_for group, html: { remote: true }, &block - end + if admin_view + form_for [:admin, group], html: { remote: true }, &block + else + form_for group, html: { remote: true }, &block + end end end diff --git a/app/helpers/group_helper.rb b/app/helpers/group_helper.rb index f946816b..457b2f4b 100644 --- a/app/helpers/group_helper.rb +++ b/app/helpers/group_helper.rb @@ -1,10 +1,13 @@ module GroupHelper def display_name(group) return t('views.urls.index.table.collection_filter.none') if group.default? + group.name end def group_names_and_ids_for_select(groups) - groups.collect { |group| [display_name(group), group['id'] ] }.sort_by{ |group| [ group.first == "No Collection" ? 0 : 1, group.first.downcase ] } + groups.collect do |group| + [display_name(group), group['id']] + end.sort_by { |group| [group.first == "No Collection" ? 0 : 1, group.first.downcase] } end end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb index 6758afbb..7043ff07 100644 --- a/app/helpers/sessions_helper.rb +++ b/app/helpers/sessions_helper.rb @@ -5,7 +5,7 @@ def sign_in(user) user.reload session[:remember_token] = user.remember_token # expire in four hours - session[:expires_at] = Time.now + 4.hours + session[:expires_at] = Time.zone.now + 4.hours self.current_user = user end @@ -19,7 +19,7 @@ def current_user=(user) def current_user # if the user is carrying an expired session, just return nil and force them to sign in again - if session[:expires_at] && session[:expires_at] > Time.now + if session[:expires_at] && session[:expires_at] > Time.zone.now @current_user ||= User.find_by_remember_token(session[:remember_token]) end end diff --git a/app/helpers/url_helper.rb b/app/helpers/url_helper.rb index 8725dfb4..50c1e437 100644 --- a/app/helpers/url_helper.rb +++ b/app/helpers/url_helper.rb @@ -7,7 +7,7 @@ def display_long_url(url, max_length = 20) truncate(url, length: max_length) end - def display_keyword_url(keyword, max_length = 35) + def display_keyword_url(keyword, _max_length = 35) # "#{request.host_with_port}/#{truncate(keyword, length: max_length)}" "#{request.host_with_port}/#{keyword}" end diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js new file mode 100644 index 00000000..7c3021d7 --- /dev/null +++ b/app/javascript/packs/application.js @@ -0,0 +1,18 @@ +/* eslint no-console:0 */ +// This file is automatically compiled by Webpack, along with any other files +// present in this directory. You're encouraged to place your actual application logic in +// a relevant structure within app/javascript and only use these pack files to reference +// that code so it'll be compiled. +// +// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate +// layout file, like app/views/layouts/application.html.erb + + +// Uncomment to copy all static images under ../images to the output folder and reference +// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) +// or the `imagePath` JavaScript helper below. +// +// const images = require.context('../images', true) +// const imagePath = (name) => images(name, true) + +console.log('Hello World from Webpacker') diff --git a/app/middleware/handle_bad_encoding_middleware.rb b/app/middleware/handle_bad_encoding_middleware.rb new file mode 100644 index 00000000..5564f0a4 --- /dev/null +++ b/app/middleware/handle_bad_encoding_middleware.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Handling malformed quesy strings like /?%= +class HandleBadEncodingMiddleware + def initialize(app) + @app = app + end + + def call(env) + begin + Rack::Utils.parse_nested_query(env['QUERY_STRING'].to_s) + rescue Rack::Utils::InvalidParameterError + env['QUERY_STRING'] = '' + end + + @app.call(env) + end +end diff --git a/app/middleware/invalid_data_interceptor.rb b/app/middleware/invalid_data_interceptor.rb index 91459510..2084e296 100644 --- a/app/middleware/invalid_data_interceptor.rb +++ b/app/middleware/invalid_data_interceptor.rb @@ -4,7 +4,11 @@ def initialize(app) end def call(env) - query = Rack::Utils.parse_nested_query(env['QUERY_STRING'].to_s) rescue :bad_query + query = begin + Rack::Utils.parse_nested_query(env['QUERY_STRING'].to_s) + rescue StandardError + :bad_query + end headers = { 'Content-Type' => 'text/plain' } @@ -14,4 +18,4 @@ def call(env) @app.call(env) end end -end \ No newline at end of file +end diff --git a/app/models/admin/announcement.rb b/app/models/admin/announcement.rb index 6ccf331e..19857ea0 100644 --- a/app/models/admin/announcement.rb +++ b/app/models/admin/announcement.rb @@ -2,18 +2,17 @@ # # Table name: starburst_announcements # -#id int(11) No -#title text Yes -#body text Yes -#start_delivering_at datetime Yes -#stop_delivering_at datetime Yes -#limit_to_users text Yes -#created_at datetime Yes -#updated_at datetime Yes -#category text Yes +# id int(11) No +# title text Yes +# body text Yes +# start_delivering_at datetime Yes +# stop_delivering_at datetime Yes +# limit_to_users text Yes +# created_at datetime Yes +# updated_at datetime Yes +# category text Yes # models/announcement.rb class Admin::Announcement < ApplicationRecord self.table_name = 'starburst_announcements' - end diff --git a/app/models/audit.rb b/app/models/audit.rb index 39f6fccd..7cd7347d 100644 --- a/app/models/audit.rb +++ b/app/models/audit.rb @@ -13,5 +13,4 @@ class Audit < ApplicationRecord self.table_name = 'versions' belongs_to :user, foreign_key: 'whodunnit' - end diff --git a/app/models/click.rb b/app/models/click.rb index 1c950d42..88b71edf 100644 --- a/app/models/click.rb +++ b/app/models/click.rb @@ -11,42 +11,34 @@ class Click < ApplicationRecord belongs_to :url - scope :within, ->(time) do - where('created_at >= ?', time.ago) - end + scope :within, lambda { |duration_ago| + where('created_at >= ?', duration_ago.ago) + } - # Click.group_by_time_ago - # Purpose: Group the clicks by a specified time period - # and count the number of clicks over that period + ## + # Purpose: Group the clicks by a specified duration + # and count the number of clicks over that duration # Arguments: - # time - a Duration object (e.g. 5.days) + # duration_ago - a Duration object (e.g. 5.days) # format - a string used to determine the grouping of the clicks. # For instance, to group by day, the format string could # be '%m/%d' - def self.group_by_time_ago(time, format) - duration_type = time.parts[0][0] - # Initialize the return array - click_counts = {} - (0..time.parts[0][1] - 1).reverse_each do |time_ago| - click_counts[time_ago.send(duration_type).ago.strftime(format)] = 0 - end - - all.within(time) - .group("date_format(created_at, '%Y%m%d %H')") - .count - .each do |result| - time_label = DateTime.parse(result[0]) - .in_time_zone(Time.zone) - .strftime(format) + # Returns: a hash of the form { formatted time string => count } + ## + def self.group_by_time_ago(duration, format) + clicks_hash = all.within(duration) + .group("date_format(created_at, '%Y%m%d %H')") + .count + .each_with_object({}) do |(datetime, count), acc| + time_label = Time.zone.parse(datetime).strftime(format) - if click_counts[time_label].nil? - click_counts[time_label] = result[1] - else - click_counts[time_label] += result[1] - end + # if label not in use, count is nil so cast nil to 0 for previous count + prev_count = acc[time_label].to_i + acc[time_label] = prev_count + count end - click_counts + # sorted by datetime + clicks_hash.sort_by { |datetime, _clicks| Time.zone.parse(datetime) }.to_h end def self.max_by_day diff --git a/app/models/group.rb b/app/models/group.rb index 4fde2575..984fb635 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -12,8 +12,8 @@ class Group < ApplicationRecord include VersionUser has_paper_trail - after_save :version_history before_destroy :version_history + after_save :version_history has_many :groups_users, dependent: :destroy has_many :users, through: :groups_users @@ -30,9 +30,9 @@ class Group < ApplicationRecord end # all groups that arent the default group for a user - scope :not_default, -> do + scope :not_default, lambda { where('id not in ( select default_group_id from users )') - end + } def user?(user) users.exists?(user.id) @@ -41,7 +41,7 @@ def user?(user) def add_user(user, send_group_change_notifications = false) users << user unless users.exists?(user.id) groups_users.find_by_user_id(user).update( - notify_user_changes: send_group_change_notifications + notify_user_changes: send_group_change_notifications ) end @@ -63,7 +63,7 @@ def version_history h = " Current Name: #{name}
" h.concat "Current Description: #{description}
" h.concat "

History


" - self.versions.each do |v| + versions.each do |v| g = v.reify unless v.event.equal? "create" h.concat "What Happened: #{v.event}
" h.concat "Who Made It: #{self.class.version_user(v)}
" @@ -72,10 +72,9 @@ def version_history h.concat "Date of Change: #{g ? g.updated_at : 'N/A'}
" h.concat "

" end - self.versions.each do |v| + versions.each do |v| v.version_history = h v.save end end - end diff --git a/app/models/ip_location.rb b/app/models/ip_location.rb index a4025ff7..88445388 100644 --- a/app/models/ip_location.rb +++ b/app/models/ip_location.rb @@ -1,3 +1,3 @@ class IpLocation < ApplicationRecord - self.table_name = 'ip2location_db1' + self.table_name = 'ip2location_db1' end diff --git a/app/models/transfer_request.rb b/app/models/transfer_request.rb index 22fa7465..6dc449cc 100644 --- a/app/models/transfer_request.rb +++ b/app/models/transfer_request.rb @@ -14,11 +14,12 @@ class TransferRequest < ApplicationRecord include VersionUser has_paper_trail - after_save :version_history + before_save :pre_approve before_destroy :version_history + after_save :version_history - belongs_to :from_group, foreign_key: 'from_group_id', class_name: 'Group' - belongs_to :to_group, foreign_key: 'to_group_id', class_name: 'Group' + belongs_to :from_group, class_name: 'Group' + belongs_to :to_group, class_name: 'Group' belongs_to :from_user, foreign_key: 'from_group_requestor_id', class_name: 'User' belongs_to :to_user, primary_key: 'default_group_id', foreign_key: 'to_group_id', class_name: 'User' @@ -28,8 +29,6 @@ class TransferRequest < ApplicationRecord validate :from_user_must_own_urls_or_from_user_is_admin - before_save :pre_approve - scope :pending, -> { where(status: 'pending') } def pre_approve @@ -47,6 +46,7 @@ def from_user_must_own_urls_or_from_user_is_admin url_groups = urls.map(&:group_id) user_groups = from_user.groups.pluck(:id) return if (url_groups - user_groups).empty? || from_group.try(:admin?) || from_user.try(:admin?) + errors.add(:from_user, 'must own URLs') end @@ -69,28 +69,25 @@ def reject! save end - def version_history h = " Requested By: #{from_user.internet_id}
" h.concat " To User: #{to_user.internet_id}
" h.concat " Current Status: #{status}
" h.concat "
URLs:
" - self.urls.each do |url| + urls.each do |url| h.concat "#{url.keyword}
" end h.concat "

History


" - self.versions.each do |v| - g = v.reify #unless v.event.equal? "create" + versions.each do |v| + g = v.reify # unless v.event.equal? "create" h.concat "What Happened: #{v.event}
" h.concat "Who Made It: #{self.class.version_user(v)}
" h.concat "Previous Status: #{g ? g.status : 'N/A'}
" h.concat "

" end - self.versions.each do |v| + versions.each do |v| v.version_history = h v.save end end - - end diff --git a/app/models/url.rb b/app/models/url.rb index 8b775d85..0817df92 100644 --- a/app/models/url.rb +++ b/app/models/url.rb @@ -16,9 +16,9 @@ class Url < ApplicationRecord include VersionUser - has_paper_trail :ignore => [:total_clicks] - after_save :version_history + has_paper_trail ignore: [:total_clicks] before_destroy :version_history + after_save :version_history belongs_to :group has_many :clicks, dependent: :delete_all @@ -54,44 +54,41 @@ class Url < ApplicationRecord end end - scope :created_by_id, ->(group_id) do - where('group_id = ?', group_id) - end + scope :created_by_id, lambda { |group_id| + where(group_id: group_id) + } - scope :created_by_ids, ->(group_ids) do - where('group_id IN (?)', group_ids) - end + scope :created_by_ids, lambda { |group_ids| + where(group_id: group_ids) + } - scope :created_by_name, ->(group_name) do + scope :created_by_name, lambda { |group_name| owner_to_search = "%#{group_name}%" possible_groups = Group.where('name LIKE ?', owner_to_search).map(&:id) - where('group_id IN (?)', possible_groups) - end + where(group_id: possible_groups) + } - scope :by_keyword, ->(keyword) do + scope :by_keyword, lambda { |keyword| where('keyword LIKE ?', "%#{keyword.try(:downcase)}%") - end + } - scope :by_keywords, ->(keywords) do - where('keyword IN (?)', "%#{keywords.map(&:downcase)}%") - end + scope :by_keywords, lambda { |keywords| + where(keyword: "%#{keywords.map(&:downcase)}%") + } - scope :not_in_pending_transfer_request, -> do + scope :not_in_pending_transfer_request, lambda { url_ids = TransferRequest.pending.joins(:urls).pluck(:url_id) where.not("#{table_name}.id IN (?)", url_ids) if url_ids.present? - end + } def add_click!(client_ip) - client_ip_decimal = IPAddr.new(client_ip).to_i begin @location = IpLocation.where('? >= ip_from AND ? < ip_to', client_ip_decimal, client_ip_decimal) - if(@location.first!.country_code) - country_code = @location.first!.country_code - end - rescue + country_code = @location.first!.country_code if @location.first!.country_code + rescue StandardError country_code = '' end @@ -106,30 +103,28 @@ def click_data_to_csv csv << [url, keyword, click.country_code, click.created_at.to_s(:created_on_formatted)] end end - return %w{url keyword country_code url_created_on}.to_csv + data + %w[url keyword country_code url_created_on].to_csv + data end def self.to_csv(duration, time_unit, urls) # ex: http://localhost:3000/shortener/urls/csv/24/days.csv - col_names = nil - formats = {days: '%m/%d', hours: '%I:%M%p'} + col_names = %w[url keyword] + formats = { days: '%m/%d', hours: '%I:%M%p' } data = CSV.generate(headers: true) do |csv| urls.each do |url| res = url.clicks.group_by_time_ago(duration.to_i.send(time_unit), formats[time_unit.to_sym]) - col_names = %w{url keyword} + res.keys + col_names += res.keys col_values = [url.url, url.keyword] + res.values csv << col_values end end - return col_names.to_csv + data + col_names.to_csv + data end def check_for_valid_url - begin - URI.parse(url) - rescue URI::InvalidURIError - errors.add(:url, 'is not valid.') - end + URI.parse(url) + rescue URI::InvalidURIError + errors.add(:url, 'is not valid.') end def version_history @@ -137,7 +132,7 @@ def version_history h.concat "Current Keyword: #{keyword}
" h.concat "Current Group: #{group.name}
" h.concat "

History


" - self.versions.each do |v| + versions.each do |v| g = v.reify unless v.event.equal? "create" h.concat "What Happened: #{v.event}
" h.concat "Who Made It: #{self.class.version_user(v)}
" @@ -147,10 +142,9 @@ def version_history h.concat "Date of Change: #{g ? g.updated_at : 'N/A'}
" h.concat "

" end - self.versions.each do |v| + versions.each do |v| v.version_history = h v.save end end - end diff --git a/app/models/user.rb b/app/models/user.rb index 3f22a5e4..7f895144 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -16,11 +16,9 @@ class User < ApplicationRecord has_many :groups, through: :groups_users belongs_to :default_group, - foreign_key: 'default_group_id', class_name: 'Group' belongs_to :context_group, - foreign_key: 'context_group_id', class_name: 'Group' validates :context_group, presence: true diff --git a/app/policies/admin/announcement_policy.rb b/app/policies/admin/announcement_policy.rb index 4fe3f7a5..95f50d84 100644 --- a/app/policies/admin/announcement_policy.rb +++ b/app/policies/admin/announcement_policy.rb @@ -1,5 +1,4 @@ class Admin::AnnouncementPolicy < ApplicationPolicy - def index? user_has_access? end @@ -24,7 +23,7 @@ def destroy? def user_has_access? return true if user.admin? + false end - -end \ No newline at end of file +end diff --git a/app/policies/admin_membership_policy.rb b/app/policies/admin_membership_policy.rb index 4d751c42..c140f755 100644 --- a/app/policies/admin_membership_policy.rb +++ b/app/policies/admin_membership_policy.rb @@ -1,6 +1,5 @@ # app/policies/admin_membership_policy.rb -class AdminMembershipPolicy < Struct.new(:user, :admin_membership) - +AdminMembershipPolicy = Struct.new(:user, :admin_membership) do def index? user.admin? end @@ -12,5 +11,4 @@ def create? def destroy? user.admin? end - -end \ No newline at end of file +end diff --git a/app/policies/application_policy.rb b/app/policies/application_policy.rb index c70bb9f0..5b4cbaad 100644 --- a/app/policies/application_policy.rb +++ b/app/policies/application_policy.rb @@ -3,6 +3,7 @@ class ApplicationPolicy def initialize(user, record) raise Pundit::NotAuthorizedError, "must be logged in" unless user + @user = user @record = record end diff --git a/app/policies/audit_policy.rb b/app/policies/audit_policy.rb index c3945512..f779bd88 100644 --- a/app/policies/audit_policy.rb +++ b/app/policies/audit_policy.rb @@ -1,5 +1,4 @@ class AuditPolicy < ApplicationPolicy - def index? user_has_access? end @@ -12,7 +11,7 @@ def show? def user_has_access? return true if user.admin? + false end - -end \ No newline at end of file +end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 679a087f..2bf660d6 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -1,5 +1,4 @@ class GroupPolicy < ApplicationPolicy - def index? user_has_access? end @@ -26,7 +25,7 @@ def user_has_access? return true if user.admin? return true if record.is_a?(Group) && record.users.exists?(user.id) return true if record.is_a?(Array) && record.all? { |rec| rec.users.exists?(user.id) } + false end - -end \ No newline at end of file +end diff --git a/app/policies/transfer_request_policy.rb b/app/policies/transfer_request_policy.rb index 3f1284a4..bacb3c33 100644 --- a/app/policies/transfer_request_policy.rb +++ b/app/policies/transfer_request_policy.rb @@ -1,5 +1,4 @@ class TransferRequestPolicy < ApplicationPolicy - def edit? can_crud? end @@ -32,9 +31,8 @@ def confirm? def can_crud? return true if user.admin? - return true if (user.in_group?(Group.find(record.from_group_id)) || user.in_group?(Group.find(record.to_group_id))) + return true if user.in_group?(Group.find(record.from_group_id)) || user.in_group?(Group.find(record.to_group_id)) + false end - - -end \ No newline at end of file +end diff --git a/app/policies/url_policy.rb b/app/policies/url_policy.rb index 46d94927..24fd6ecc 100644 --- a/app/policies/url_policy.rb +++ b/app/policies/url_policy.rb @@ -1,5 +1,4 @@ class UrlPolicy < ApplicationPolicy - def index? user_has_access? end @@ -33,8 +32,8 @@ def destroy? def user_has_access? return true if user.admin? return true if record.is_a?(Url) && record.group.user?(user) - return true if record.is_a?(Array) && record.all? { |rec| rec.group.user?(user)} + return true if record.is_a?(Array) && record.all? { |rec| rec.group.user?(user) } + false end - -end \ No newline at end of file +end diff --git a/app/services/user_lookup_service.rb b/app/services/user_lookup_service.rb index c284bb56..bdea088d 100644 --- a/app/services/user_lookup_service.rb +++ b/app/services/user_lookup_service.rb @@ -3,15 +3,20 @@ class UserLookupService def initialize(params = nil) - @connection = Net::LDAP.new( - YAML.load(File.open('config/ldap.yml')) - ) + # ldap.yml may contain embedded erb to + # fetch environment variables so parse this + # before loading the config + raw_config = File.read('config/ldap.yml') + processed_config = ERB.new(raw_config).result + + @connection = Net::LDAP.new(YAML.load(processed_config)) @query = params[:query] if params @query_type = params[:query_type] if params end def search return nil unless @query.present? && @query_type.present? + results = nil if @connection.bind if @query_type == 'all' @@ -46,8 +51,14 @@ def search end end return nil unless results + results = results.promote(results.detect { |x| x[:uid] == [@query] }) - results = results.map { |x| { umndid: umndid(x), display: display(x), internet_id: internet_id(x), display_name: result_name(x) } }.flatten unless results.blank? + if results.present? + results = results.map do |x| + { umndid: umndid(x), display: display(x), internet_id: internet_id(x), + display_name: result_name(x) } + end.flatten + end results end @@ -58,15 +69,15 @@ def umndid(x) end def display_name(x) - x.try(:displayname).try(:first) ? x.try(:displayname).try(:first) : 'Name not available' + x.try(:displayname).try(:first) || 'Name not available' end def result_name(x) - x.try(:displayname).try(:first) ? x.try(:displayname).try(:first) : '(name not available)' + x.try(:displayname).try(:first) || '(name not available)' end def internet_id(x) - x.try(:uid).try(:first) ? x.try(:uid).try(:first) : 'Internet ID not available' + x.try(:uid).try(:first) || 'Internet ID not available' end def display(x) diff --git a/app/services/user_lookup_service_skeleton.rb b/app/services/user_lookup_service_skeleton.rb index 97c93ec1..16589d1c 100644 --- a/app/services/user_lookup_service_skeleton.rb +++ b/app/services/user_lookup_service_skeleton.rb @@ -16,24 +16,23 @@ def search # Query the cache or make a connection to LDAP to find results. # results = Rails.cache.fetch("#{@query}/#{@query_type}/search", expires_in: 12.hours) do - # Query LDAP - # Left as an example - # if @connection.bind - # @connection.search( - # filter: get_filter, - # return_result: true - # ) - # end + # Query LDAP + # Left as an example + # if @connection.bind + # @connection.search( + # filter: get_filter, + # return_result: true + # ) + # end # end # Dummy results - results = [ + [ umndid: 'testuid', display: 'Ryan Doe (testinternetid@umn.edu)', internet_id: 'testinternetid', display_name: 'Ryan Doe' ] - results end private diff --git a/app/views/errors/not_found.html.erb b/app/views/errors/not_found.html.erb index 7d2731ec..dc450af5 100644 --- a/app/views/errors/not_found.html.erb +++ b/app/views/errors/not_found.html.erb @@ -1,5 +1,10 @@ -
-

Not Found

- -

The short URL you requested does not exist.

-
+
+

404

+

Not Found

+ +
+

+ We can’t seem to find what you’re looking for. This could be caused by a bad link or a mistyped URL. You could try the University of Minnesota Search. +

+
+
diff --git a/app/views/group_memberships/_form.html.erb b/app/views/group_memberships/_form.html.erb index 4d0bd157..7a35cc24 100644 --- a/app/views/group_memberships/_form.html.erb +++ b/app/views/group_memberships/_form.html.erb @@ -2,7 +2,7 @@ <%= form_tag(group_members_path, remote: true, method: 'post', id: 'search-form', class: 'new_member') do %>
<%= label_tag :people_search, t('views.group_memberships.index.form.add_someone') %> - <%= text_field_tag 'people_search', nil, class: 'form-control' %> + <%= text_field_tag 'people_search', nil, class: 'form-control', required: true %> <%= t('views.group_memberships.index.form.help') %>. @@ -11,7 +11,7 @@
<%= button_tag type: "submit", class: 'btn btn-primary add-new-group-member', data: { confirm: t('views.group_memberships.index.form.submit_confirm') } do %> - <%= t('views.group_memberships.index.form.submit') %> + <%= t('views.group_memberships.index.form.submit') %> <% end %> <% end %> diff --git a/app/views/layouts/_header.html.erb b/app/views/layouts/_header.html.erb index f843ac1b..14510ae2 100644 --- a/app/views/layouts/_header.html.erb +++ b/app/views/layouts/_header.html.erb @@ -18,7 +18,7 @@ diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index f84f3893..42620d86 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -6,7 +6,7 @@ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= yield :head %> - <%= favicon_link_tag 'https://langtest.umn.edu/static/images/favicon.ico' %> + <%= favicon_link_tag '/favicon.ico' %> <%= render 'layouts/shim' %> diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 00000000..4df19493 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,70 @@ +module.exports = function(api) { + var validEnv = ['development', 'test', 'production'] + var currentEnv = api.env() + var isDevelopmentEnv = api.env('development') + var isProductionEnv = api.env('production') + var isTestEnv = api.env('test') + + if (!validEnv.includes(currentEnv)) { + throw new Error( + 'Please specify a valid `NODE_ENV` or ' + + '`BABEL_ENV` environment variables. Valid values are "development", ' + + '"test", and "production". Instead, received: ' + + JSON.stringify(currentEnv) + + '.' + ) + } + + return { + presets: [ + isTestEnv && [ + '@babel/preset-env', + { + targets: { + node: 'current' + } + } + ], + (isProductionEnv || isDevelopmentEnv) && [ + '@babel/preset-env', + { + forceAllTransforms: true, + useBuiltIns: 'entry', + corejs: 3, + modules: false, + exclude: ['transform-typeof-symbol'] + } + ] + ].filter(Boolean), + plugins: [ + 'babel-plugin-macros', + '@babel/plugin-syntax-dynamic-import', + isTestEnv && 'babel-plugin-dynamic-import-node', + '@babel/plugin-transform-destructuring', + [ + '@babel/plugin-proposal-class-properties', + { + loose: true + } + ], + [ + '@babel/plugin-proposal-object-rest-spread', + { + useBuiltIns: true + } + ], + [ + '@babel/plugin-transform-runtime', + { + helpers: false + } + ], + [ + '@babel/plugin-transform-regenerator', + { + async: false + } + ] + ].filter(Boolean) + } +} diff --git a/bin/rails b/bin/rails index 07396602..6fb4e405 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,4 @@ #!/usr/bin/env ruby APP_PATH = File.expand_path('../config/application', __dir__) -require_relative '../config/boot' -require 'rails/commands' +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake index 17240489..4fbf10b9 100755 --- a/bin/rake +++ b/bin/rake @@ -1,4 +1,4 @@ #!/usr/bin/env ruby -require_relative '../config/boot' -require 'rake' +require_relative "../config/boot" +require "rake" Rake.application.run diff --git a/bin/setup b/bin/setup index e620b4da..90700ac4 100755 --- a/bin/setup +++ b/bin/setup @@ -1,30 +1,32 @@ #!/usr/bin/env ruby -require 'pathname' -require 'fileutils' -include FileUtils +require "fileutils" # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) +APP_ROOT = File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do - # This script is a starting point to setup your application. +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') + # Install JavaScript dependencies + system! 'bin/yarn' + # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/bin/spring b/bin/spring deleted file mode 100755 index 43731fe8..00000000 --- a/bin/spring +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true -# -# This file was generated by Bundler. -# -# The application 'spring' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("spring", "spring") diff --git a/bin/webpack b/bin/webpack new file mode 100755 index 00000000..1031168d --- /dev/null +++ b/bin/webpack @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "bundler/setup" + +require "webpacker" +require "webpacker/webpack_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::WebpackRunner.run(ARGV) +end diff --git a/bin/webpack-dev-server b/bin/webpack-dev-server new file mode 100755 index 00000000..dd966273 --- /dev/null +++ b/bin/webpack-dev-server @@ -0,0 +1,18 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" +ENV["NODE_ENV"] ||= "development" + +require "pathname" +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", + Pathname.new(__FILE__).realpath) + +require "bundler/setup" + +require "webpacker" +require "webpacker/dev_server_runner" + +APP_ROOT = File.expand_path("..", __dir__) +Dir.chdir(APP_ROOT) do + Webpacker::DevServerRunner.run(ARGV) +end diff --git a/bin/yarn b/bin/yarn new file mode 100755 index 00000000..9fab2c35 --- /dev/null +++ b/bin/yarn @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + yarn = ENV["PATH"].split(File::PATH_SEPARATOR). + select { |dir| File.expand_path(dir) != __dir__ }. + product(["yarn", "yarn.cmd", "yarn.ps1"]). + map { |dir, file| File.expand_path(file, dir) }. + find { |file| File.executable?(file) } + + if yarn + exec yarn, *ARGV + else + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/config.ru b/config.ru index f7ba0b52..4a3c09a6 100644 --- a/config.ru +++ b/config.ru @@ -1,5 +1,6 @@ # This file is used by Rack-based servers to start the application. -require_relative 'config/environment' +require_relative "config/environment" run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb index edcdc3fc..6f41908e 100644 --- a/config/application.rb +++ b/config/application.rb @@ -3,12 +3,18 @@ require 'csv' require 'rails/all' +# Handle bad url encodings +require_relative '../app/middleware/handle_bad_encoding_middleware' + # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module Z class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 6.1 + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. @@ -17,7 +23,11 @@ class Application < Rails::Application config.time_zone = 'Central Time (US & Canada)' # config.middleware.insert_before Rack::Runtime, 'InvalidDataInterceptor' config.action_dispatch.ip_spoofing_check = false + + config.middleware.insert 0, Rack::UTF8Sanitizer config.middleware.use Rack::Deflater - config.exceptions_app = self.routes + config.middleware.insert_before Rack::Runtime, HandleBadEncodingMiddleware + + config.exceptions_app = routes end end diff --git a/config/cable.yml b/config/cable.yml index aa4e8327..bbe3d7a3 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,10 +1,10 @@ -# Action Cable uses Redis by default to administer connections, channels, and sending/receiving messages over the WebSocket. -production: - adapter: redis - url: redis://localhost:6379/1 - development: adapter: async test: - adapter: async + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: z_production diff --git a/config/database_ci.yml b/config/database_ci.yml new file mode 100644 index 00000000..3131c824 --- /dev/null +++ b/config/database_ci.yml @@ -0,0 +1,15 @@ +default: &default + adapter: mysql2 + host: <%= ENV['DB_HOST'] %> + port: <%= ENV['DB_PORT'] %> + username: <%= ENV['DB_USERNAME'] %> + password: <%= ENV['DB_PASSWORD'] %> + encoding: utf8mb4 + +development: + <<: *default + database: z + +test: + <<: *default + database: z_test diff --git a/config/deploy.rb b/config/deploy.rb index 367112ea..796083dc 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -2,7 +2,7 @@ # lock '3.6.1' set :application, 'z' -set :repo_url, 'git@github.umn.edu:latis-sw/z.git' +set :repo_url, 'git@github.com:UMN-LATIS/z.git' set :rbenv_ruby, File.read('.ruby-version').strip # Default branch is :master @@ -11,8 +11,6 @@ # Default deploy_to directory is /var/www/my_app_name set :deploy_to, '/swadm/web/z/' - - # Default value for :scm is :git # set :scm, :git @@ -30,7 +28,8 @@ append :linked_files, 'config/database.yml', 'config/secrets.yml', 'config/ldap.yml' # Default value for linked_dirs is [] -append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system' +append :linked_dirs, 'log', 'tmp/pids', 'tmp/cache', 'tmp/sockets', 'public/system', 'public/packs', '.bundle', + 'node_modules' # Default value for default_env is {} # set :default_env, { path: "/opt/ruby/bin:$PATH" } @@ -47,3 +46,17 @@ end after 'deploy:symlink:release', 'deploy:apache' + +# Compile assets on every deployment, even if JS and CSS have not changed +# See: https://github.com/rails/webpacker/blob/master/docs/deployment.md +before "deploy:assets:precompile", "deploy:yarn_install" +namespace :deploy do + desc "Run rake yarn install" + task :yarn_install do + on roles(:web) do + within release_path do + execute("cd #{release_path} && yarn install --silent --no-progress --no-audit --no-optional") + end + end + end +end diff --git a/config/deploy/production.rb b/config/deploy/production.rb index beabcd6a..5681de3b 100644 --- a/config/deploy/production.rb +++ b/config/deploy/production.rb @@ -7,8 +7,6 @@ # server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value # server 'db.example.com', user: 'deploy', roles: %w{db} - - # role-based syntax # ================== @@ -17,14 +15,12 @@ # property set. Specify the username and a domain or IP for the server. # Don't use `:all`, it's a meta role. -role :app, %w(swadm@cla-z-prd.oit.umn.edu) -role :web, %w(swadm@cla-z-prd.oit.umn.edu) -role :db, %w(swadm@cla-z-prd.oit.umn.edu) -role :app, %w(swadm@cla-z-prd-2.oit.umn.edu) -role :web, %w(swadm@cla-z-prd-2.oit.umn.edu) -role :db, %w(swadm@cla-z-prd-2.oit.umn.edu) - - +role :app, %w[swadm@cla-z-prd.oit.umn.edu] +role :web, %w[swadm@cla-z-prd.oit.umn.edu] +role :db, %w[swadm@cla-z-prd.oit.umn.edu] +# role :app, %w(swadm@cla-z-prd-2.oit.umn.edu) +# role :web, %w(swadm@cla-z-prd-2.oit.umn.edu) +# role :db, %w(swadm@cla-z-prd-2.oit.umn.edu) # Configuration # ============= @@ -34,8 +30,6 @@ # http://capistranorb.com/documentation/getting-started/configuration/ # Feel free to add new variables to customise your setup. - - # Custom SSH Options # ================== # You may pass any option but keep in mind that net/ssh understands a diff --git a/config/deploy/remotedev.rb b/config/deploy/remotedev.rb index 66333f5b..fd4b3b22 100644 --- a/config/deploy/remotedev.rb +++ b/config/deploy/remotedev.rb @@ -1,5 +1,5 @@ # Default branch is :master -#set :branch, :develop +# set :branch, :develop ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp # server-based syntax @@ -11,8 +11,6 @@ # server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value # server 'db.example.com', user: 'deploy', roles: %w{db} - - # role-based syntax # ================== @@ -21,10 +19,9 @@ # property set. Specify the username and a domain or IP for the server. # Don't use `:all`, it's a meta role. -role :app, %w{swadm@cla-z-dev.oit.umn.edu} -role :web, %w{swadm@cla-z-dev.oit.umn.edu} -role :db, %w{swadm@cla-z-dev.oit.umn.edu} - +role :app, %w[swadm@cla-z-dev.oit.umn.edu] +role :web, %w[swadm@cla-z-dev.oit.umn.edu] +role :db, %w[swadm@cla-z-dev.oit.umn.edu] # Configuration # ============= diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb index 17b4258f..6e333192 100644 --- a/config/deploy/staging.rb +++ b/config/deploy/staging.rb @@ -1,5 +1,5 @@ # Default branch is :master -#set :branch, :develop +# set :branch, :develop ask :branch, `git rev-parse --abbrev-ref HEAD`.chomp # server-based syntax @@ -11,8 +11,6 @@ # server 'example.com', user: 'deploy', roles: %w{app web}, other_property: :other_value # server 'db.example.com', user: 'deploy', roles: %w{db} - - # role-based syntax # ================== @@ -21,10 +19,9 @@ # property set. Specify the username and a domain or IP for the server. # Don't use `:all`, it's a meta role. -role :app, %w{swadm@cla-z-stage.oit.umn.edu} -role :web, %w{swadm@cla-z-stage.oit.umn.edu} -role :db, %w{swadm@cla-z-stage.oit.umn.edu} - +role :app, %w[swadm@cla-z-stage.oit.umn.edu] +role :web, %w[swadm@cla-z-stage.oit.umn.edu] +role :db, %w[swadm@cla-z-stage.oit.umn.edu] # Configuration # ============= diff --git a/config/environments/development.rb b/config/environments/development.rb index 2ff7c52f..db5471d6 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,19 +1,37 @@ +require "active_support/core_ext/integer/time" + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded on - # every request. This slows down response time but is perfect for development + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false # Do not eager load code on boot. config.eager_load = false - + # Show full error reports. - # set this to false to test 404 pages config.consider_all_requests_local = true - config.cache_store = :memory_store, { size: 32.megabytes } + # Enable/disable caching. By default caching is disabled. + # Run rails dev:cache to toggle caching. + if Rails.root.join('tmp/caching-dev.txt').exist? + config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end + + # Store uploaded files on the local file system (see config/storage.yml for options). + # config.active_storage.service = :local # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false @@ -23,9 +41,18 @@ # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. @@ -34,17 +61,18 @@ # Suppress logger output for asset requests. config.assets.quiet = true - # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker - - # enable this line to test local 404 - # config.consider_all_requests_local = false - - # Set the omniauth provider + + # Uncomment if you wish to allow Action Cable access from any origin. + # config.action_cable.disable_request_forgery_protection = true + config.omniauth_provider = 'developer' - # config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor end diff --git a/config/environments/production.rb b/config/environments/production.rb index 421969d1..d87eb115 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -19,7 +19,7 @@ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. - config.assets.js_compressor = :uglifier + config.assets.js_compressor = Uglifier.new(harmony: true) # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. @@ -42,6 +42,12 @@ # config.action_cable.mount_path = nil # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + + # We don't want to force_ssl right now. + # Z intentionally is able to vend shortened URLs + # over http when requested, so that we don't introduce cross protocol issues + # for end users. Instead, we use an apache mod_rewrite rule to force any + # requests to the user interface side of Z to be https. # config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information @@ -92,25 +98,26 @@ config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { - address: 'mail.socsci.umn.edu', - port: 587, - enable_starttls_auto: true } + address: 'mail.socsci.umn.edu', + port: 587, + enable_starttls_auto: true + } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true -# config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor + # config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor config.middleware.use ExceptionNotification::Rack, email: { - email_prefix: Rails.env, - sender_address: '"Z Exception Notifier" ', - exception_recipients: ["web-app-errors@cla.umn.edu"] + email_prefix: Rails.env, + sender_address: '"Z Exception Notifier" ', + exception_recipients: ["web-app-errors@cla.umn.edu"] }, - :slack => { - :webhook_url => "https://hooks.slack.com/services/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", - :channel => "#sw_z_exceptions", - :username => "Z Production Environment", - :additional_parameters => { - :icon_emoji => ":boom:", - :mrkdwn => true - } + slack: { + webhook_url: "https://hooks.slack.com/services/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", + channel: "#sw_z_exceptions", + username: "Z Production Environment", + additional_parameters: { + icon_emoji: ":boom:", + mrkdwn: true + } } end diff --git a/config/environments/remotedev.rb b/config/environments/remotedev.rb index 426ed2ec..e655651c 100644 --- a/config/environments/remotedev.rb +++ b/config/environments/remotedev.rb @@ -19,7 +19,7 @@ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. - config.assets.js_compressor = :uglifier + config.assets.js_compressor = Uglifier.new(harmony: true) # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. @@ -42,7 +42,7 @@ # config.action_cable.mount_path = nil # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. @@ -90,31 +90,29 @@ config.omniauth_provider = 'shibboleth' config.shib_return_url = 'https://login.umn.edu/idp/profile/Logout' - config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { - address: 'mail.socsci.umn.edu', - port: 587, - enable_starttls_auto: true } + address: 'mail.socsci.umn.edu', + port: 587, + enable_starttls_auto: true + } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true -# config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor + # config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor config.middleware.use ExceptionNotification::Rack, email: { - email_prefix: Rails.env, - sender_address: '"Z Exception Notifier" ', - exception_recipients: ["web-app-errors@cla.umn.edu"] + email_prefix: Rails.env, + sender_address: '"Z Exception Notifier" ', + exception_recipients: ["web-app-errors@cla.umn.edu"] }, - :slack => { - :webhook_url => "https://hooks.slack.com/services/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", - :channel => "#sw_z_exceptions", - :username => "Z Remote Dev Environment", - :additional_parameters => { - :icon_emoji => ":zap:", - :mrkdwn => true - } + slack: { + webhook_url: "https://hooks.slack.com/services/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", + channel: "#sw_z_exceptions", + username: "Z Remote Dev Environment", + additional_parameters: { + icon_emoji: ":zap:", + mrkdwn: true + } } - - end diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 650f4900..34beba87 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -19,7 +19,7 @@ config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. - config.assets.js_compressor = :uglifier + config.assets.js_compressor = Uglifier.new(harmony: true) # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. @@ -42,7 +42,7 @@ # config.action_cable.mount_path = nil # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true # Use the lowest log level to ensure availability of diagnostic information # when problems arise. @@ -90,29 +90,29 @@ config.omniauth_provider = 'shibboleth' config.shib_return_url = 'https://login.umn.edu/idp/profile/Logout' - config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { - address: 'mail.socsci.umn.edu', - port: 587, - enable_starttls_auto: true } + address: 'mail.socsci.umn.edu', + port: 587, + enable_starttls_auto: true + } config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true -# config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor + # config.middleware.insert_before Rack::Runtime, InvalidDataInterceptor config.middleware.use ExceptionNotification::Rack, email: { - email_prefix: Rails.env, - sender_address: '"Z Exception Notifier" ', - exception_recipients: ["web-app-errors@cla.umn.edu"] + email_prefix: Rails.env, + sender_address: '"Z Exception Notifier" ', + exception_recipients: ["web-app-errors@cla.umn.edu"] }, - :slack => { - :webhook_url => "https://hooks.slack.com/services/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", - :channel => "#sw_z_exceptions", - :username => "Z Staging Environment", - :additional_parameters => { - :icon_emoji => ":zap:", - :mrkdwn => true - } + slack: { + webhook_url: "https://hooks.slack.com/services/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", + channel: "#sw_z_exceptions", + username: "Z Staging Environment", + additional_parameters: { + icon_emoji: ":zap:", + mrkdwn: true + } } end diff --git a/config/environments/test.rb b/config/environments/test.rb index 5a0ef6d7..eeb9468a 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -5,7 +5,7 @@ # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! - config.cache_classes = true + config.cache_classes = false # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that diff --git a/config/initializers/ajax_datatables_rails.rb b/config/initializers/ajax_datatables_rails.rb index 2546cefe..0ff243b9 100644 --- a/config/initializers/ajax_datatables_rails.rb +++ b/config/initializers/ajax_datatables_rails.rb @@ -1,7 +1,10 @@ AjaxDatatablesRails.configure do |config| - # available options for db_adapter are: :oracle, :pg, :mysql2, :sqlite3 - config.db_adapter = :mysql2 + # available options for db_adapter are: :pg, :mysql, :mysql2, :sqlite, :sqlite3 + # config.db_adapter = :mysql2 - # available options for paginator are: :simple_paginator, :kaminari, :will_paginate - # config.paginator = :simple_paginator + # Or you can use your rails environment adapter if you want a generic dev and production + config.db_adapter = Rails.configuration.database_configuration[Rails.env]['adapter'].to_sym + + # available options for orm are: :active_record, :mongoid + # config.orm = :active_record end diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb index 51639b67..89d2efab 100644 --- a/config/initializers/application_controller_renderer.rb +++ b/config/initializers/application_controller_renderer.rb @@ -1,6 +1,8 @@ # Be sure to restart your server when you modify this file. -# ApplicationController.renderer.defaults.merge!( -# http_host: 'example.org', -# https: false -# ) +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/arel_regex_mysql.rb b/config/initializers/arel_regex_mysql.rb index 4d4e7e36..93813648 100644 --- a/config/initializers/arel_regex_mysql.rb +++ b/config/initializers/arel_regex_mysql.rb @@ -8,13 +8,16 @@ module Visitors class MySQL < Arel::Visitors::ToSql private - def visit_Arel_Nodes_Regexp o, collector - infix_value o, collector, ' REGEXP ' + # rubocop:disable Naming/MethodName + + def visit_Arel_Nodes_Regexp(obj, collector) + infix_value obj, collector, ' REGEXP ' end - def visit_Arel_Nodes_NotRegexp o, collector - infix_value o, collector, ' NOT REGEXP ' + def visit_Arel_Nodes_NotRegexp(obj, collector) + infix_value obj, collector, ' NOT REGEXP ' end + # rubocop:enable Naming/MethodName end end end diff --git a/config/initializers/array_promote.rb b/config/initializers/array_promote.rb index 328d3b0a..d1911592 100644 --- a/config/initializers/array_promote.rb +++ b/config/initializers/array_promote.rb @@ -1,6 +1,7 @@ class Array def promote(promoted_element) return self unless (found_index = find_index(promoted_element)) + unshift(delete_at(found_index)) end end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 01ef3e66..96018a9d 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -6,6 +6,9 @@ # Add additional assets to the asset load path # Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. # Rails.application.config.assets.precompile += %w( search.js ) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 59385cdf..33699c30 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,7 +1,8 @@ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } +# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. -# Rails.backtrace_cleaner.remove_silencers! +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code +# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". +Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] diff --git a/config/initializers/callback_terminator.rb b/config/initializers/callback_terminator.rb index 0c97ce21..3a9b5dc8 100644 --- a/config/initializers/callback_terminator.rb +++ b/config/initializers/callback_terminator.rb @@ -4,5 +4,4 @@ # Rails 5.0 default, so it is introduced as a configuration option to ensure # that apps made with earlier versions of Rails are not affected when upgrading. - # ActiveSupport.halt_callback_chains_on_return_false = false diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 00000000..35d0f26f --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,30 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy +# For further information see the following documentation +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy + +# Rails.application.config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # If you are using webpack-dev-server then specify webpack-dev-server host +# policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? + +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end + +# If you are using UJS then enable automatic nonce generation +# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } + +# Set the nonce only to specific directives +# Rails.application.config.content_security_policy_nonce_directives = %w(script-src) + +# Report CSP violations to a specified URI +# For further information see the following documentation: +# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only +# Rails.application.config.content_security_policy_report_only = true diff --git a/config/initializers/date_formats.rb b/config/initializers/date_formats.rb index f2fe92a9..70397ec9 100644 --- a/config/initializers/date_formats.rb +++ b/config/initializers/date_formats.rb @@ -1,3 +1,3 @@ # config/initializers/time_formats.rb Time::DATE_FORMATS[:created_on_formatted] = "%m/%d/%Y" -Time::DATE_FORMATS[:short_ordinal] = lambda { |time| time.strftime("%B #{time.day.ordinalize}") } +Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") } diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 4a994e1e..fd60d015 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,4 +1,6 @@ # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password] +Rails.application.config.filter_parameters += %i[ + password passw secret token _key crypt salt certificate otp ssn +] diff --git a/config/initializers/lograge.rb b/config/initializers/lograge.rb index 7cdeaf97..9f97c6e7 100644 --- a/config/initializers/lograge.rb +++ b/config/initializers/lograge.rb @@ -2,8 +2,8 @@ config.lograge.keep_original_rails_log = true config.lograge.enabled = true config.lograge.logger = ::Logger.new "#{Rails.root}/log/lograge_#{Rails.env}.log" - config.lograge.formatter = Lograge::Formatters::Json.new - config.lograge.custom_options = lambda do |event| - { time: Time.now } + config.lograge.formatter = Lograge::Formatters::Json.new + config.lograge.custom_options = lambda do |_event| + { time: Time.zone.now } end end diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 4c655ec0..7d731854 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -2,16 +2,18 @@ provider :developer unless Rails.env.production? || Rails.env.staging? || Rails.env.remotedev? provider :shibboleth, { uid_field: 'umnDID', - :extra_fields => [ + extra_fields: [ :isGuest ] } provider :shibboleth_passive, { uid_field: 'umnDID', - :extra_fields => [ + extra_fields: [ :isGuest ] } end OmniAuth.config.logger = Rails.logger + +OmniAuth.config.allowed_request_methods = %i[post get] diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb new file mode 100644 index 00000000..00f64d71 --- /dev/null +++ b/config/initializers/permissions_policy.rb @@ -0,0 +1,11 @@ +# Define an application-wide HTTP permissions policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.permissions_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb index 0afc01e3..facd0c46 100644 --- a/config/initializers/sentry.rb +++ b/config/initializers/sentry.rb @@ -5,9 +5,9 @@ # Set tracesSampleRate to 1.0 to capture 100% # of transactions for performance monitoring. # We recommend adjusting this value in production - if Rails.env.production? - config.traces_sample_rate = 0 - else - config.traces_sample_rate = 0.5 - end -end \ No newline at end of file + config.traces_sample_rate = if Rails.env.production? + 0 + else + 0.5 + end +end diff --git a/config/initializers/time_in_ms.rb b/config/initializers/time_in_ms.rb index e5a7e90e..9dc3156e 100644 --- a/config/initializers/time_in_ms.rb +++ b/config/initializers/time_in_ms.rb @@ -1,5 +1,5 @@ class Time def to_ms - (self.to_f * 1000.0).to_i + (to_f * 1000.0).to_i end end diff --git a/config/ldap_ci.yml b/config/ldap_ci.yml new file mode 100644 index 00000000..3776bf98 --- /dev/null +++ b/config/ldap_ci.yml @@ -0,0 +1,8 @@ +:host: ldapauth.umn.edu +:port: 636 +:encryption: :simple_tls +:base: o=University of Minnesota,c=US +:auth: + :method: :simple + :username: <%= ENV['LDAP_USERNAME'] %> + :password: <%= ENV['LDAP_PASSWORD'] %> diff --git a/config/puma.rb b/config/puma.rb index c7f311f8..d9b3e836 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,22 +1,31 @@ # Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers a minimum and maximum. +# The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum, this matches the default thread size of Active Record. +# and maximum; this matches the default thread size of Active Record. # -threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i -threads threads_count, threads_count +max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +threads min_threads_count, max_threads_count -# Specifies the `port` that Puma will listen on to receive requests, default is 3000. +# Specifies the `worker_timeout` threshold that Puma will use to wait before +# terminating a worker in development environments. # -port ENV.fetch("PORT") { 3000 } +worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } # Specifies the `environment` that Puma will run in. # environment ENV.fetch("RAILS_ENV") { "development" } +# Specifies the `pidfile` that Puma will use. +pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } + # Specifies the number of `workers` to boot in clustered mode. -# Workers are forked webserver processes. If using threads and workers together +# Workers are forked web server processes. If using threads and workers together # the concurrency of the application would be max `threads` * `workers`. # Workers do not work on JRuby or Windows (both of which do not support # processes). @@ -26,22 +35,9 @@ # Use the `preload_app!` method when specifying a `workers` number. # This directive tells Puma to first boot the application and load code # before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. If you use this option -# you need to make sure to reconnect any threads in the `on_worker_boot` -# block. +# process behavior so workers use less memory. # # preload_app! -# The code in the `on_worker_boot` will be called if you are using -# clustered mode by specifying a number of `workers`. After each worker -# process is booted this block will be run, if you are using `preload_app!` -# option you will want to use this block to reconnect to any threads -# or connections that may have been created at application boot, Ruby -# cannot share connections between processes. -# -# on_worker_boot do -# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) -# end - # Allow puma to be restarted by `rails restart` command. plugin :tmp_restart diff --git a/config/routes.rb b/config/routes.rb index b03da691..6cef3ac1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,7 +3,7 @@ # http://guides.rubyonrails.org/routing.html mount Starburst::Engine => "/starburst" - + # Handle API namespace :api do namespace :v1 do @@ -70,8 +70,8 @@ post 'confirm', on: :member end - resources :move_to_group, only: [:new, :create] - resources :batch_delete, only: [:new, :create] + resources :move_to_group, only: %i[new create] + resources :batch_delete, only: %i[new create] # groups groups index get # groups/:id groups show get @@ -85,8 +85,8 @@ # groups/:id/members/new group_memberships new get # groups/:id/members/create group_memberships create put # groups/:id/members/destroy group_memberships destroy delete - resources :members, only: [:index, :new, :create, :destroy], controller: 'group_memberships' do - get 'new/:search_terms', to: 'group_memberships#new', on: :collection + resources :members, only: %i[index new create destroy], controller: 'group_memberships' do + get 'new/:search_terms', to: 'group_memberships#new', on: :collection end end @@ -99,11 +99,10 @@ # api_keys/:id/update api_keys update post # api_keys/create api_keys create put # api_keys/destroy api_keys destroy delete - resources :api_keys, only: [:index, :create] do + resources :api_keys, only: %i[index create] do delete 'delete', on: :collection end - # group_context/update group_context show get resources :group_context, only: [:show] @@ -113,7 +112,7 @@ # admin/transfer_requests/confirm admin::transfer_requests confirm post # admin/transfer_requests/create admin::transfer_requests create put # admin/transfer_requests/:id/show admin::transfer_requests show get - resources :transfer_requests, only: [:index, :new, :create, :show] do + resources :transfer_requests, only: %i[index new create show] do post 'confirm', on: :member end @@ -122,7 +121,7 @@ # admin/urls/update admin::urls update post # admin/urls/delete admin::urls destroy delete # admin/urls/create admin::urls create put - resources :urls, only: [:index, :edit, :show, :update, :destroy, :create] do + resources :urls, only: %i[index edit show update destroy create] do get 'datatable', to: 'urls_datatable#index', on: :collection get 'csv/:duration/:time_unit', on: :collection, @@ -132,7 +131,7 @@ # admin/audits/:search admin::urls index get # admin/audits/:id admin::urls show get - resources :audits, only: [:index, :show] do + resources :audits, only: %i[index show] do get 'datatable', to: 'audits_datatable#index', on: :collection end @@ -142,25 +141,22 @@ # admin/members/:id admin::members show get # admin/members/delete admin::members destroy delete # admin/members/create admin::members create put - resources :members, only: [:index, :new, :create, :destroy], controller: 'members' do + resources :members, only: %i[index new create destroy], controller: 'members' do get 'new/:search_terms', to: 'members#new', on: :collection end # admin/admins admin::admins index get # admin/admins/delete admin::admins destroy delete # admin/admins/create admin::admins create put - resources :admins, only: [:index, :destroy, :create] - - resources :announcements, only: [:index, :new, :edit, :show, :update, :destroy, :create] - + resources :admins, only: %i[index destroy create] + resources :announcements, only: %i[index new edit show update destroy create] end end match "/404", to: "errors#not_found", via: :all match "/500", to: "errors#internal_server_error", via: :all - + # /:keyword redirect index get get '/*keyword', to: 'redirect#index' - end diff --git a/config/spring.rb b/config/spring.rb index c9119b40..9fa7863f 100644 --- a/config/spring.rb +++ b/config/spring.rb @@ -1,6 +1,6 @@ -%w( +%w[ .ruby-version .rbenv-vars tmp/restart.txt tmp/caching-dev.txt -).each { |path| Spring.watch(path) } +].each { |path| Spring.watch(path) } diff --git a/config/storage.yml b/config/storage.yml new file mode 100644 index 00000000..d32f76e8 --- /dev/null +++ b/config/storage.yml @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/config/webpack/development.js b/config/webpack/development.js new file mode 100644 index 00000000..c5edff94 --- /dev/null +++ b/config/webpack/development.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/config/webpack/environment.js b/config/webpack/environment.js new file mode 100644 index 00000000..d16d9af7 --- /dev/null +++ b/config/webpack/environment.js @@ -0,0 +1,3 @@ +const { environment } = require('@rails/webpacker') + +module.exports = environment diff --git a/config/webpack/production.js b/config/webpack/production.js new file mode 100644 index 00000000..be0f53aa --- /dev/null +++ b/config/webpack/production.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'production' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/config/webpack/test.js b/config/webpack/test.js new file mode 100644 index 00000000..c5edff94 --- /dev/null +++ b/config/webpack/test.js @@ -0,0 +1,5 @@ +process.env.NODE_ENV = process.env.NODE_ENV || 'development' + +const environment = require('./environment') + +module.exports = environment.toWebpackConfig() diff --git a/config/webpacker.yml b/config/webpacker.yml new file mode 100644 index 00000000..1ce554f2 --- /dev/null +++ b/config/webpacker.yml @@ -0,0 +1,104 @@ +# Note: You must restart bin/webpack-dev-server for changes to take effect + +default: &default + source_path: app/javascript + source_entry_path: packs + public_root_path: public + public_output_path: packs + cache_path: tmp/cache/webpacker + webpack_compile_output: true + + # Additional paths webpack should lookup modules + # ['app/assets', 'engine/foo/app/assets'] + additional_paths: [] + + # Reload manifest.json on all requests so we reload latest compiled packs + cache_manifest: false + + # Extract and emit a css file + extract_css: false + + static_assets_extensions: + - .jpg + - .jpeg + - .png + - .gif + - .tiff + - .ico + - .svg + - .eot + - .otf + - .ttf + - .woff + - .woff2 + + extensions: + - .mjs + - .js + - .sass + - .scss + - .css + - .module.sass + - .module.scss + - .module.css + - .png + - .svg + - .gif + - .jpeg + - .jpg + +development: + <<: *default + compile: true + + # Reference: https://webpack.js.org/configuration/dev-server/ + dev_server: + https: false + host: localhost + port: 3035 + public: localhost:3035 + hmr: true + # Inline should be set to true if using HMR + inline: true + overlay: true + compress: true + disable_host_check: true + use_local_ip: false + quiet: false + pretty: false + headers: + "Access-Control-Allow-Origin": "*" + watch_options: + ignored: "**/node_modules/**" + +test: + <<: *default + compile: true + + # Compile test packs to a separate directory + public_output_path: packs-test + +# mirroring production settings +remotedev: + <<: + *default + # Production depends on precompilation of packs prior to booting for performance. + compile: false + + # Extract and emit a css file + extract_css: true + + # Cache manifest.json for performance + cache_manifest: true + +production: + <<: *default + + # Production depends on precompilation of packs prior to booting for performance. + compile: false + + # Extract and emit a css file + extract_css: true + + # Cache manifest.json for performance + cache_manifest: true diff --git a/db/migrate/20160524143250_create_groups.rb b/db/migrate/20160524143250_create_groups.rb index c95e2286..b924b66f 100644 --- a/db/migrate/20160524143250_create_groups.rb +++ b/db/migrate/20160524143250_create_groups.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateGroups < ActiveRecord::Migration[5.0] def change create_table :groups do |t| diff --git a/db/migrate/20160524143258_create_urls.rb b/db/migrate/20160524143258_create_urls.rb index ae1302dd..5fa28df7 100644 --- a/db/migrate/20160524143258_create_urls.rb +++ b/db/migrate/20160524143258_create_urls.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateUrls < ActiveRecord::Migration[5.0] def change create_table :urls do |t| diff --git a/db/migrate/20160524143305_create_clicks.rb b/db/migrate/20160524143305_create_clicks.rb index 06e1a700..2544ab62 100644 --- a/db/migrate/20160524143305_create_clicks.rb +++ b/db/migrate/20160524143305_create_clicks.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateClicks < ActiveRecord::Migration[5.0] def change create_table :clicks do |t| diff --git a/db/migrate/20160524143306_create_users.rb b/db/migrate/20160524143306_create_users.rb index f1a0668c..9d570c87 100644 --- a/db/migrate/20160524143306_create_users.rb +++ b/db/migrate/20160524143306_create_users.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| diff --git a/db/migrate/20160524143313_create_groups_users.rb b/db/migrate/20160524143313_create_groups_users.rb index 7e320310..d63b2fcb 100644 --- a/db/migrate/20160524143313_create_groups_users.rb +++ b/db/migrate/20160524143313_create_groups_users.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateGroupsUsers < ActiveRecord::Migration[5.0] def change create_table :groups_users do |t| diff --git a/db/migrate/20160524143319_create_transfer_requests.rb b/db/migrate/20160524143319_create_transfer_requests.rb index 91dabcd6..ffaea057 100644 --- a/db/migrate/20160524143319_create_transfer_requests.rb +++ b/db/migrate/20160524143319_create_transfer_requests.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateTransferRequests < ActiveRecord::Migration[5.0] def change create_table :transfer_requests do |t| diff --git a/db/migrate/20160524143325_create_transfer_request_urls.rb b/db/migrate/20160524143325_create_transfer_request_urls.rb index 6df3dc17..8a651bb9 100644 --- a/db/migrate/20160524143325_create_transfer_request_urls.rb +++ b/db/migrate/20160524143325_create_transfer_request_urls.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateTransferRequestUrls < ActiveRecord::Migration[5.0] def change create_table :transfer_request_urls, id: false do |t| diff --git a/db/migrate/20160602213409_add_remember_token_to_users.rb b/db/migrate/20160602213409_add_remember_token_to_users.rb index 5f2098d3..b45b9b62 100644 --- a/db/migrate/20160602213409_add_remember_token_to_users.rb +++ b/db/migrate/20160602213409_add_remember_token_to_users.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddRememberTokenToUsers < ActiveRecord::Migration[5.0] def change add_column :users, :remember_token, :string diff --git a/db/migrate/20160607201831_change_context_group_id_to_not_null.rb b/db/migrate/20160607201831_change_context_group_id_to_not_null.rb index 287168d5..c41f6bb8 100644 --- a/db/migrate/20160607201831_change_context_group_id_to_not_null.rb +++ b/db/migrate/20160607201831_change_context_group_id_to_not_null.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class ChangeContextGroupIdToNotNull < ActiveRecord::Migration[5.0] def change change_column :users, :context_group_id, :integer, :null => false diff --git a/db/migrate/20160608164913_change_notify_user_changes_to_not_null.rb b/db/migrate/20160608164913_change_notify_user_changes_to_not_null.rb index cd5d4fe8..1f6b8bbd 100644 --- a/db/migrate/20160608164913_change_notify_user_changes_to_not_null.rb +++ b/db/migrate/20160608164913_change_notify_user_changes_to_not_null.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class ChangeNotifyUserChangesToNotNull < ActiveRecord::Migration[5.0] def change change_column :groups_users, :notify_user_changes, :boolean, :null => false diff --git a/db/migrate/20160615155059_change_context_group_id_to_nullable.rb b/db/migrate/20160615155059_change_context_group_id_to_nullable.rb index 0724eca8..a2059665 100644 --- a/db/migrate/20160615155059_change_context_group_id_to_nullable.rb +++ b/db/migrate/20160615155059_change_context_group_id_to_nullable.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class ChangeContextGroupIdToNullable < ActiveRecord::Migration[5.0] def change change_column :users, :context_group_id, :integer, :null => true diff --git a/db/migrate/20160721210808_add_index_to_urls.rb b/db/migrate/20160721210808_add_index_to_urls.rb index e87d7da2..e902d8de 100644 --- a/db/migrate/20160721210808_add_index_to_urls.rb +++ b/db/migrate/20160721210808_add_index_to_urls.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddIndexToUrls < ActiveRecord::Migration[5.0] def change add_index :urls, :keyword, unique: true diff --git a/db/migrate/20170117151420_add_from_group_requestor_id_to_transfer_requests.rb b/db/migrate/20170117151420_add_from_group_requestor_id_to_transfer_requests.rb index 11d2e545..8da606b6 100644 --- a/db/migrate/20170117151420_add_from_group_requestor_id_to_transfer_requests.rb +++ b/db/migrate/20170117151420_add_from_group_requestor_id_to_transfer_requests.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddFromGroupRequestorIdToTransferRequests < ActiveRecord::Migration[5.0] def change add_column :transfer_requests, :from_group_requestor_id, :integer, :after => :from_group_id diff --git a/db/migrate/20170120205321_add_perid_to_umndid_table.rb b/db/migrate/20170120205321_add_perid_to_umndid_table.rb index 4ac51b50..77834ce2 100644 --- a/db/migrate/20170120205321_add_perid_to_umndid_table.rb +++ b/db/migrate/20170120205321_add_perid_to_umndid_table.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddPeridToUmndidTable < ActiveRecord::Migration[5.0] def change create_table :perid_umndid do |t| diff --git a/db/migrate/20170126170109_change_urls_url_to_text.rb b/db/migrate/20170126170109_change_urls_url_to_text.rb index bd2e5030..9c0bcdae 100644 --- a/db/migrate/20170126170109_change_urls_url_to_text.rb +++ b/db/migrate/20170126170109_change_urls_url_to_text.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class ChangeUrlsUrlToText < ActiveRecord::Migration[5.0] def self.up change_column :urls, :url, :text diff --git a/db/migrate/20170206214947_add_default_to_transfer_request.rb b/db/migrate/20170206214947_add_default_to_transfer_request.rb index b08d3c29..7b8148b3 100644 --- a/db/migrate/20170206214947_add_default_to_transfer_request.rb +++ b/db/migrate/20170206214947_add_default_to_transfer_request.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddDefaultToTransferRequest < ActiveRecord::Migration[5.0] def change change_column :transfer_requests, :status, :string, default: 'pending' diff --git a/db/migrate/20170214195130_change_url_url_to_text.rb b/db/migrate/20170214195130_change_url_url_to_text.rb index 435ce9b1..dc1461fd 100644 --- a/db/migrate/20170214195130_change_url_url_to_text.rb +++ b/db/migrate/20170214195130_change_url_url_to_text.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class ChangeUrlUrlToText < ActiveRecord::Migration[5.0] def self.up change_column :urls, :url, :text diff --git a/db/migrate/20170222161436_create_versions.rb b/db/migrate/20170222161436_create_versions.rb index e458e0a2..4605300a 100644 --- a/db/migrate/20170222161436_create_versions.rb +++ b/db/migrate/20170222161436_create_versions.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + # This migration creates the `versions` table, the only schema PT requires. # All other migrations PT provides are optional. class CreateVersions < ActiveRecord::Migration[4.2] diff --git a/db/migrate/20170308204605_add_whodunnit_email_to_versions.rb b/db/migrate/20170308204605_add_whodunnit_email_to_versions.rb index 36d2196a..daedfffc 100644 --- a/db/migrate/20170308204605_add_whodunnit_email_to_versions.rb +++ b/db/migrate/20170308204605_add_whodunnit_email_to_versions.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddWhodunnitEmailToVersions < ActiveRecord::Migration[5.0] def change add_column :versions, :whodunnit_email, :string diff --git a/db/migrate/20170308204626_add_whodunnit_name_to_versions.rb b/db/migrate/20170308204626_add_whodunnit_name_to_versions.rb index 14e4de86..3973c38a 100644 --- a/db/migrate/20170308204626_add_whodunnit_name_to_versions.rb +++ b/db/migrate/20170308204626_add_whodunnit_name_to_versions.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddWhodunnitNameToVersions < ActiveRecord::Migration[5.0] def change add_column :versions, :whodunnit_name, :string diff --git a/db/migrate/20170321184711_add_uid_to_perid_umndid.rb b/db/migrate/20170321184711_add_uid_to_perid_umndid.rb index b7ca8c3e..7e91246a 100644 --- a/db/migrate/20170321184711_add_uid_to_perid_umndid.rb +++ b/db/migrate/20170321184711_add_uid_to_perid_umndid.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddUidToPeridUmndid < ActiveRecord::Migration[5.0] def change add_column :perid_umndid, :uid, :string diff --git a/db/migrate/20170329193403_set_total_clicks_default_in_db.rb b/db/migrate/20170329193403_set_total_clicks_default_in_db.rb index e9dd31ae..54692100 100644 --- a/db/migrate/20170329193403_set_total_clicks_default_in_db.rb +++ b/db/migrate/20170329193403_set_total_clicks_default_in_db.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class SetTotalClicksDefaultInDb < ActiveRecord::Migration[5.0] def up change_column :urls, :total_clicks, :integer, default: 0 diff --git a/db/migrate/20170405202937_create_frequently_asked_questions.rb b/db/migrate/20170405202937_create_frequently_asked_questions.rb index 6985eb8c..9e9aa61c 100644 --- a/db/migrate/20170405202937_create_frequently_asked_questions.rb +++ b/db/migrate/20170405202937_create_frequently_asked_questions.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class CreateFrequentlyAskedQuestions < ActiveRecord::Migration[5.0] def change create_table :frequently_asked_questions do |t| diff --git a/db/migrate/20170427153202_create_announcement_tables.starburst.rb b/db/migrate/20170427153202_create_announcement_tables.starburst.rb index 8635ca34..dd20faf1 100644 --- a/db/migrate/20170427153202_create_announcement_tables.starburst.rb +++ b/db/migrate/20170427153202_create_announcement_tables.starburst.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + # This migration comes from starburst (originally 20141004214002) class CreateAnnouncementTables < ActiveRecord::Migration[4.2] def change diff --git a/db/migrate/20170427153203_add_category_to_starburst_announcements.starburst.rb b/db/migrate/20170427153203_add_category_to_starburst_announcements.starburst.rb index 19469f23..e23b6a60 100644 --- a/db/migrate/20170427153203_add_category_to_starburst_announcements.starburst.rb +++ b/db/migrate/20170427153203_add_category_to_starburst_announcements.starburst.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + # This migration comes from starburst (originally 20141112140703) class AddCategoryToStarburstAnnouncements < ActiveRecord::Migration[4.2] def change diff --git a/db/migrate/20170427153204_add_index_and_uniqueness_to_announcement_views.starburst.rb b/db/migrate/20170427153204_add_index_and_uniqueness_to_announcement_views.starburst.rb index ca9ba520..4decf557 100644 --- a/db/migrate/20170427153204_add_index_and_uniqueness_to_announcement_views.starburst.rb +++ b/db/migrate/20170427153204_add_index_and_uniqueness_to_announcement_views.starburst.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + # This migration comes from starburst (originally 20141209221904) class AddIndexAndUniquenessToAnnouncementViews < ActiveRecord::Migration[4.2] def change diff --git a/db/migrate/20170509175646_add_version_history_to_versions.rb b/db/migrate/20170509175646_add_version_history_to_versions.rb index 9d7cdfdd..d498a0ad 100644 --- a/db/migrate/20170509175646_add_version_history_to_versions.rb +++ b/db/migrate/20170509175646_add_version_history_to_versions.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddVersionHistoryToVersions < ActiveRecord::Migration[5.0] def change add_column :versions, :version_history, :text diff --git a/db/migrate/20170606004310_add_secret_key_to_user.rb b/db/migrate/20170606004310_add_secret_key_to_user.rb index 40ba8913..944227bd 100644 --- a/db/migrate/20170606004310_add_secret_key_to_user.rb +++ b/db/migrate/20170606004310_add_secret_key_to_user.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddSecretKeyToUser < ActiveRecord::Migration[5.0] def change add_column :users, :secret_key, :string diff --git a/db/migrate/20180524122211_add_ip_lookup_table.rb b/db/migrate/20180524122211_add_ip_lookup_table.rb index 4407bda6..5e8ff4d6 100644 --- a/db/migrate/20180524122211_add_ip_lookup_table.rb +++ b/db/migrate/20180524122211_add_ip_lookup_table.rb @@ -1,3 +1,5 @@ +# rubocop:disable all + class AddIpLookupTable < ActiveRecord::Migration[5.0] def change create_table :ip2location_db1 do |t| diff --git a/db/migrate/20210719171642_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb b/db/migrate/20210719171642_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb new file mode 100644 index 00000000..4146a818 --- /dev/null +++ b/db/migrate/20210719171642_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb @@ -0,0 +1,12 @@ +# rubocop:disable all + +# This migration comes from active_storage (originally 20180723000244) +class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] + def up + return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) + + if table_exists?(:active_storage_blobs) + add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 2c91fd4e..9e4876bc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,17 +2,17 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `rails +# db:schema:load`. When creating a new database, `rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_05_24_122211) do +ActiveRecord::Schema.define(version: 2021_07_19_171642) do - create_table "clicks", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "clicks", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "country_code" t.integer "url_id" t.datetime "created_at", null: false @@ -20,7 +20,7 @@ t.index ["url_id"], name: "index_clicks_on_url_id" end - create_table "frequently_asked_questions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "frequently_asked_questions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "header" t.text "question" t.text "answer" @@ -28,14 +28,14 @@ t.datetime "updated_at", null: false end - create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "name" t.string "description" t.datetime "created_at", null: false t.datetime "updated_at", null: false end - create_table "groups_users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "groups_users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.integer "group_id" t.integer "user_id" t.boolean "notify_user_changes", default: false, null: false @@ -43,7 +43,7 @@ t.index ["user_id"], name: "index_groups_users_on_user_id" end - create_table "ip2location_db1", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "ip2location_db1", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.integer "ip_from", unsigned: true t.integer "ip_to", unsigned: true t.string "country_code", limit: 2 @@ -53,13 +53,13 @@ t.index ["ip_to"], name: "index_ip2location_db1_on_ip_to" end - create_table "perid_umndid", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "perid_umndid", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "perid" t.string "umndid" t.string "uid" end - create_table "starburst_announcement_views", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "starburst_announcement_views", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.integer "user_id" t.integer "announcement_id" t.datetime "created_at" @@ -67,7 +67,7 @@ t.index ["user_id", "announcement_id"], name: "starburst_announcement_view_index", unique: true end - create_table "starburst_announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "starburst_announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.text "title" t.text "body" t.datetime "start_delivering_at" @@ -78,14 +78,14 @@ t.text "category" end - create_table "transfer_request_urls", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "transfer_request_urls", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.integer "transfer_request_id" t.integer "url_id" t.index ["transfer_request_id"], name: "index_transfer_request_urls_on_transfer_request_id" t.index ["url_id"], name: "index_transfer_request_urls_on_url_id" end - create_table "transfer_requests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "transfer_requests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.integer "to_group_id" t.integer "from_group_id" t.integer "from_group_requestor_id" @@ -97,7 +97,7 @@ t.index ["to_group_id"], name: "index_transfer_requests_on_to_group_id" end - create_table "urls", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "urls", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.text "url" t.string "keyword" t.integer "total_clicks", default: 0 @@ -109,7 +109,7 @@ t.index ["keyword"], name: "index_urls_on_keyword", unique: true end - create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| + create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "uid" t.integer "context_group_id" t.integer "default_group_id" @@ -127,7 +127,7 @@ t.integer "item_id", null: false t.string "event", null: false t.string "whodunnit" - t.text "object", limit: 4294967295 + t.text "object", size: :long t.datetime "created_at" t.string "whodunnit_email" t.string "whodunnit_name" diff --git a/db/seeds.rb b/db/seeds.rb index 42d47ea0..4db45b41 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -14,64 +14,71 @@ if Rails.env.development? User.create( - [{uid: 'zx8gky5wf'}, - {uid: '2qggnq4v3'}, - {uid: '46suz2aru'}, - {uid: '3dci3yxub'}, - {uid: '5scyi59j8', admin: true}] + [{ uid: 'zx8gky5wf' }, + { uid: '2qggnq4v3' }, + { uid: '46suz2aru' }, + { uid: '3dci3yxub' }, + { uid: '5scyi59j8', admin: true }] ) Group.create( - [{name: 'LATIS', description: 'This is the LATIS test group'}, - {name: 'DCL', description: 'This is the DCL test group'}, - {name: 'CLA PR', description: 'This is the CLA PR test group'}, - {name: 'DASH', description: 'This is the DASH test group'}] + [{ name: 'LATIS', description: 'This is the LATIS test group' }, + { name: 'DCL', description: 'This is the DCL test group' }, + { name: 'CLA PR', description: 'This is the CLA PR test group' }, + { name: 'DASH', description: 'This is the DASH test group' }] ) Url.create( - [ - { - url: 'http://www.google.com', - keyword: 'goog', - total_clicks: 9, - group: User.first.context_group - }, - { - url: 'http://www.umn.edu', - keyword: 'umn', - total_clicks: 3, - group: User.last.context_group - } - ] + [ + { + url: 'http://www.google.com', + keyword: 'goog', + total_clicks: 9, + group: User.first.context_group + }, + { + url: 'http://www.umn.edu', + keyword: 'umn', + total_clicks: 3, + group: User.last.context_group + } + ] ) Click.create( - [{country_code: 'US', url_id: Url.first.id}, - {country_code: 'US', url_id: Url.first.id}, - {country_code: 'US', url_id: Url.first.id}, - {country_code: 'CA', url_id: Url.first.id}, - {country_code: 'UZ', url_id: Url.first.id}, - {country_code: 'CA', url_id: Url.first.id}, - {country_code: 'RU', url_id: Url.first.id}, - {country_code: 'CU', url_id: Url.first.id}, - {country_code: 'RU', url_id: Url.first.id}, - {country_code: 'CN', url_id: Url.last.id}, - {country_code: 'CN', url_id: Url.last.id}, - {country_code: 'CN', url_id: Url.last.id}] + [{ country_code: 'US', url_id: Url.first.id }, + { country_code: 'US', url_id: Url.first.id }, + { country_code: 'US', url_id: Url.first.id }, + { country_code: 'CA', url_id: Url.first.id }, + { country_code: 'UZ', url_id: Url.first.id }, + { country_code: 'CA', url_id: Url.first.id }, + { country_code: 'RU', url_id: Url.first.id }, + { country_code: 'CU', url_id: Url.first.id }, + { country_code: 'RU', url_id: Url.first.id }, + { country_code: 'CN', url_id: Url.last.id }, + { country_code: 'CN', url_id: Url.last.id }, + { country_code: 'CN', url_id: Url.last.id }] ) end FrequentlyAskedQuestion.create( - [{header: 'general', question: 'What is z.umn.edu (Z)?', answer: 'Z is a URL shortening service which allows for longer URLs to be be shortened. A shortened URL is helpful for social media, printed pieces, or just sharing with others.'}, - {header: 'general', question: 'When should I use z.umn.edu?', answer: 'We recommend using Z for cases in which you need a shortened URL for University-related content that will be published or posted for many users to view, or for material which may need to be retyped by users.'}, - {header: 'general', question: 'Who can create a Z link?', answer: 'Anybody with a University of Minnesota X500 login may create URLs. The URLs that are created are accessible to anyone, with no need for an X500 account. This means you can create a URL and share it with non-UMN audiences.'}, - {header: 'general', question: 'Are there limitations on the use of the “custom” field?', answer: 'We reserve the right to revoke “custom” URLs if the short name is intended to defraud or deceive, or if it is in violation of the University of Minnesota Acceptable Use policy. We recommend you avoid using custom URLs that are too generic or which may be confusing to users.'}, - {header: 'general', question: 'What if the custom URL I want is already in use?', answer: 'Once a URL has been claimed by creating a custom URL, no other URL can be created using the same URL. If it looks like a URL is claimed, but no longer in use, you can reach out to us. We’ll ask the current owner if they’re willing to relinquish it.'}, - {header: 'general', question: 'How long are URLs active?', answer: 'URLs never expire.'}, - {header: 'general', question: 'What happens to the URLs I created if I graduate or leave the U?', answer: 'The ownership of a URL can be transferred to another individual or group to ensure they can be updated and modified. The owner can do this themselves right from the site.'}, - {header: 'general', question: 'Is there a limit as to how many URLs I can create and have active?', answer: 'There is currently no limit, though we request that the service be used for U-related work/projects/events only.'}, - {header: 'general', question: 'What software does Z use?', answer: 'Z is an open source application developed by LATIS at the University of Minnesota. You can view the source code and learn about installing it yourself at github.com/umn-latis/z.'}, - {header: 'general', question: 'How reliable are click counts for a given URL?', answer: 'In general, the Z counts should be reliable. The application itself definitely counts any time it redirects someone. We say "in general" because some browsers cache these types of redirects. So, if the same person clicked a given link a few times, with the same browser, Z might only count the first click.'} - ] -) \ No newline at end of file + [{ header: 'general', question: 'What is z.umn.edu (Z)?', answer: 'Z is a URL shortening service which allows for longer URLs to be be shortened. A shortened URL is helpful for social media, printed pieces, or just sharing with others.' }, + { header: 'general', question: 'When should I use z.umn.edu?', + answer: 'We recommend using Z for cases in which you need a shortened URL for University-related content that will be published or posted for many users to view, or for material which may need to be retyped by users.' }, + { header: 'general', question: 'Who can create a Z link?', + answer: 'Anybody with a University of Minnesota X500 login may create URLs. The URLs that are created are accessible to anyone, with no need for an X500 account. This means you can create a URL and share it with non-UMN audiences.' }, + { header: 'general', question: 'Are there limitations on the use of the “custom” field?', + answer: 'We reserve the right to revoke “custom” URLs if the short name is intended to defraud or deceive, or if it is in violation of the University of Minnesota Acceptable Use policy. We recommend you avoid using custom URLs that are too generic or which may be confusing to users.' }, + { header: 'general', question: 'What if the custom URL I want is already in use?', + answer: 'Once a URL has been claimed by creating a custom URL, no other URL can be created using the same URL. If it looks like a URL is claimed, but no longer in use, you can reach out to us. We’ll ask the current owner if they’re willing to relinquish it.' }, + { header: 'general', question: 'How long are URLs active?', answer: 'URLs never expire.' }, + { header: 'general', question: 'What happens to the URLs I created if I graduate or leave the U?', + answer: 'The ownership of a URL can be transferred to another individual or group to ensure they can be updated and modified. The owner can do this themselves right from the site.' }, + { header: 'general', question: 'Is there a limit as to how many URLs I can create and have active?', + answer: 'There is currently no limit, though we request that the service be used for U-related work/projects/events only.' }, + { header: 'general', question: 'What software does Z use?', + answer: 'Z is an open source application developed by LATIS at the University of Minnesota. You can view the source code and learn about installing it yourself at github.com/umn-latis/z.' }, + { header: 'general', question: 'How reliable are click counts for a given URL?', + answer: 'In general, the Z counts should be reliable. The application itself definitely counts any time it redirects someone. We say "in general" because some browsers cache these types of redirects. So, if the same person clicked a given link a few times, with the same browser, Z might only count the first click.' }] +) diff --git a/deploy_to_production.md b/deploy_to_production.md new file mode 100644 index 00000000..037934d1 --- /dev/null +++ b/deploy_to_production.md @@ -0,0 +1,163 @@ +# DEPLOYING TO PRODUCTION + +Deploying `z` to production involves a few more steps since there are multiple servers and a load balancer involved. Here are some notes. + +## 👥 THE PLAYERS + +- points to a load balancer. The service provides an SSL cert and balances traffic between: +- `cla-z-prd.oit.umn.edu`: Production server 1. +- `cla-z-prd-2.oit.umn.edu`: Production server 2. +- Your local machine will be used to verify that each production server deployment was successful. + +Just like `dev` and `staging` deployments, we'll use Ansible for updating the platform and Capistrano for deploying the app. + +## ⚡️ THE PROCESS + +### 2 WEEKS BEFORE + +1. When Z is ready for production deployment, create a release branch following gitflow style. Deploy to staging. + +2. Because Z is critical UMN infrastructure, user-impacting deployments should receive approval from the [Enterprise Change Approval Board (CAB)](https://it.umn.edu/resources-it-staff-partners/change-management/change-approval-board). + 1. Ping LATIS' CAB representative to let them know a Z deployment will be upcoming and you're submitting a CAB request. + 2. Schedule a time for deployment. Invite a [LATIS system engineer](https://neighborhood.cla.umn.edu/latis/people/latis-staff-list) to help with load balancing hokey pokey. + 3. Complete the CAB request. + 4. Proceed if approval from CAB, or defer change if not approved. + +### DEPLOY DAY + +#### PREP + + 1. Connect to VPN + 2. Start tailing log files on production servers with `tail -f /swadm/web/z/current/log/lograge_production.log` + 3. Open Ansible Playbook locally + 4. Open z.umn.edu repo locally + 5. Open `/etc/hosts` locally. Add entries for `cla-z-prd.oit.umn.edu` and `cla-z-prd-2.oit.umn.edu`. {: #config-etc-hosts } + + ``` + # /etc/hosts + + # Z DEPLOYMENT + # Uncomment to force z.umn.edu to resolve to a particular + # production server. Used when testing that a production + # deploy is successful. + + # cla-z-prd + # 128.101.122.117 z.umn.edu + + # cla-z-prd-2 + # 128.101.122.224 z.umn.edu + ``` + + > **🙋‍♀️ Wait?! Why do we need to do this?** + > + > If you type `cla-z-prd.oit.umn.edu` into your browser and try to sign in, it'll redirect you to `z.umn.edu`. Configuring `/etc/hosts` will make sure any redirects to `z.umn.edu` also resolve to `cla-z-prd.oit.umn.edu`. + +### DEPLOYING TO EACH PRODUCTION SERVER (`cla-z-prd.oit.umn.edu`) + +Complete this for each server you're deploying to. In the example below, we'll use `cla-z-prd.oit.umn.edu` as our first target. + +1. Take `cla-z-prd-oit.umn.edu` out of the load balancing group. This is done with the help of a [LATIS System Engineer](https://neighborhood.cla.umn.edu/latis/people/latis-staff-list). + +2. Wait for connections to drain by monitoring the logfiles on `cla-z-prd-oit.umn.edu`. Once there's no traffic, proceed. (Note: There may be a small amount of bot (?) traffic directly to an individual host like `cla-z-prd`.). + +3. Set your local computer to resolve `z.umn.edu` to the ip address of the `cla-z-prd-oit.umn.edu`. On a mac, this means editing `/etc/hosts` with: + + ``` + # cla-z-prd + 128.101.122.117 z.umn.edu + ``` + + Verify that `z.umn.edu` resolves locally to the correct IP with `ping z.umn.edu`. + +#### USE ANSIBLE TO CONVERGE HOST CHANGES + +Ansible is not needed for every Z deployment, but will be required when doing things like bumping a ruby version. + +If Ansible-ing, open the [ansible playbook](https://github.umn.edu/latis-sw/ansible_playbooks) locally, then: + +1. Edit [z.yml](https://github.umn.edu/latis-sw/ansible_playbooks/blob/main/z.yml) so that `hosts` value references the correct hostname, `cla-z-prd`. See: [inventory.yml](https://github.umn.edu/latis-sw/ansible_playbooks/blob/main/inventory.yml) and [host_vars](https://github.umn.edu/latis-sw/ansible_playbooks/blob/main/host_vars/cla-z-prd.yml) for host options. + + ```yml + --- + - hosts: cla-z-prd + vars: + ruby_version: "2.7.3" + pre_tasks: + ... + ``` + +2. Login to lastpass. + + ```sh + lpass login + ``` + + Ansible will use the Z Rails Application keys stored in lastpass. + +3. Coverge the host: + + ```sh + ansible-playbook -i inventory.yml z.yml + ``` + +#### CAPISTRANO + +Use Capistrano to deploy Rails: + +1. Edit `config/deploy/production.rb` and uncomment the server to which we're deploying. For example, if deploying to `prd`: + + ```rb + # role-based syntax + ... + + role :app, %w(swadm@cla-z-prd.oit.umn.edu) + role :web, %w(swadm@cla-z-prd.oit.umn.edu) + role :db, %w(swadm@cla-z-prd.oit.umn.edu) + # role :app, %w(swadm@cla-z-prd-2.oit.umn.edu) + # role :web, %w(swadm@cla-z-prd-2.oit.umn.edu) + # role :db, %w(swadm@cla-z-prd-2.oit.umn.edu) + ... + ``` + +2. Deploy to production + + ```console + bundle exec cap production deploy + ``` + +3. Verify: + + - [x] Go to: . If we configured our `/etc/hosts` file correctly, this should resolve to our recently deployed server: `cla-z-prod.oit.umn.edu`. + - [x] Home Page renders. + - [x] Login works. + - [x] Previously created Z-links exist. + - [x] Test a previously created zlink: + - [x] Create a zlink. + - [x] Click the new zlink and verify it redirects. + - [x] Check logs for errors. + +#### NEXT STEPS + +1. Add `cla-z-prd.oit.umn.edu` back to load balanced group. +2. Monitor traffic for unexpected errors once it's receiving traffic again. +3. If all good, proceed to next server in group: `cla-z-prd-2.oit.umn.edu` and repeat the steps above. + +### POST DEPLOY + +After successful deployment: + +- [x] Log in to Team Dynamix, and mark the CAB ticket as completed. +- [x] Merge the release branch into main and develop using `git flow release finish ` +- [x] Push merged branches and tags to git: + + ``` + git checkout develop + git push + + git checkout main + git push + + git push --tags + ``` + +- [x] Check github for [latest release](https://github.com/UMN-LATIS/z/releases) diff --git a/docker-compose.yml b/docker-compose.yml index 70057a10..90fc9f91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '2' services: db: - image: mysql + image: mariadb environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: z diff --git a/index.html b/index.html deleted file mode 100644 index c4dfff95..00000000 --- a/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - Z by latis-sw - - - - - - - - -
-
-

Z

-

A URL Shortener

- - -

This project is maintained by latis-sw

- - -
-
-

-Welcome to GitHub Pages.

-

This automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new gh-pages branch locally. If you’re using GitHub Desktop, simply sync your repository and you’ll see the new branch.

-

-Designer Templates

-

We’ve crafted some handsome templates for you to use. Go ahead and click 'Continue to layouts' to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved.

-

-Creating pages manually

-

If you prefer to not use the automatic generator, push a branch named gh-pages to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.

-

-Authors and Contributors

-

You can @mention a GitHub username to generate a link to their profile. The resulting <a> element will link to the contributor’s GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.

-

-Support or Contact

-

Having trouble with Pages? Check out our documentation or contact support and we’ll help you sort it out.

-
- -
- - - - diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index 7e8d887d..5e76c050 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -1,7 +1,7 @@ # lib/tasks/db.rake namespace :db do desc 'Drop, create, migrate then seed the development database' - task reseed: [ 'db:drop', 'db:create', 'db:migrate', 'db:seed' ] do + task reseed: ['db:drop', 'db:create', 'db:migrate', 'db:seed'] do puts 'Reseeding completed.' end end diff --git a/package.json b/package.json new file mode 100644 index 00000000..aa4508eb --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "z.umn.edu", + "version": "0.0.0", + "description": "Link shortening for the University of Minnesota", + "main": "index.js", + "repository": "https://github.com/UMN-LATIS/z.git", + "author": "UMN LATIS ", + "license": "MIT", + "private": true, + "dependencies": { + "@rails/webpacker": "5.4.0", + "webpack": "^4.46.0", + "webpack-cli": "^3.3.12" + }, + "devDependencies": { + "webpack-dev-server": "^3.11.2" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 00000000..aa5998a8 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,12 @@ +module.exports = { + plugins: [ + require('postcss-import'), + require('postcss-flexbugs-fixes'), + require('postcss-preset-env')({ + autoprefixer: { + flexbox: 'no-2009' + }, + stage: 3 + }) + ] +} diff --git a/public/favicon.ico b/public/favicon.ico index e69de29b..1bdf2b5b 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/spec/apis/urls_spec.rb b/spec/apis/urls_spec.rb index de383cf7..b361f115 100644 --- a/spec/apis/urls_spec.rb +++ b/spec/apis/urls_spec.rb @@ -2,15 +2,19 @@ describe '[API: URLs]', type: :api do describe 'adding urls' do - let(:user) { FactoryGirl.create(:user) } + let(:user) { FactoryBot.create(:user) } + let(:existing_url) { FactoryBot.create(:url) } + let(:random_key) { "#{user.secret_key}012345" } let(:secret_key) { user.secret_key } let(:url1_url) { 'example.com' } let(:url2_url) { 'example.com/example' } let(:url2_keyword) { 'ex' } let(:url3_url) { 'example.com/example' } + let(:random_key) { "#{user.secret_key}012345" } + let(:existing_url) { FactoryBot.create(:url) } - it 'should let you add urls' do + it 'lets you add urls' do # Basic, singular URL payload = { urls: [ @@ -23,12 +27,12 @@ header 'Authorization', "#{user.uid}:#{token}" post '/api/v1/urls' - expect(last_response.status).to eql(200) + expect(last_response.status).to be(200) results = JSON.parse(last_response.body) expect(results.first['result']['status']).to eq('success') # Multiple URLs, one with a keyword, one with a collection name - collection = FactoryGirl.create(:group) + collection = FactoryBot.create(:group) collection.users << user payload = { urls: [ @@ -42,15 +46,14 @@ header 'Authorization', "#{user.uid}:#{token}" post '/api/v1/urls' - expect(last_response.status).to eql(200) + expect(last_response.status).to be(200) results = JSON.parse(last_response.body) results.each do |result| expect(result['result']['status']).to eq('success') end end - let(:existing_url) { FactoryGirl.create(:url) } - it 'should not let you add URLs' do + it 'does not let you add URLs' do # Taken keyword payload = { urls: [ @@ -63,7 +66,7 @@ header 'Authorization', "#{user.uid}:#{token}" post '/api/v1/urls' - expect(last_response.status).to eql(200) + expect(last_response.status).to be(200) results = JSON.parse(last_response.body) expect(results.first['result']['status']).to eq('error') @@ -79,13 +82,12 @@ header 'Authorization', "#{user.uid}:#{token}" post '/api/v1/urls' - expect(last_response.status).to eql(200) + expect(last_response.status).to be(200) results = JSON.parse(last_response.body) expect(results.first['result']['status']).to eq('error') end - let(:random_key) { "#{user.secret_key}012345" } - it 'should reject incorrect auth payloads' do + it 'rejects incorrect auth payloads' do # No username payload = { urls: [ @@ -98,7 +100,7 @@ header 'Authorization', token post '/api/v1/urls' - expect(last_response.status).to eql(401) + expect(last_response.status).to be(401) # Incorrect secret key payload = { @@ -112,7 +114,7 @@ header 'Authorization', "#{user.uid}:#{token}" post '/api/v1/urls' - expect(last_response.status).to eql(401) + expect(last_response.status).to be(401) end end end diff --git a/spec/controllers/redirect_controller_spec.rb b/spec/controllers/redirect_controller_spec.rb new file mode 100644 index 00000000..7cefd312 --- /dev/null +++ b/spec/controllers/redirect_controller_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe RedirectController do + let(:url) { FactoryBot.create(:url) } + + describe 'GET /:keyword' do + describe 'when url exists' do + it 'redirects back to the referring page if url exists' do + get :index, params: { keyword: url.keyword } + expect(response).to redirect_to url.url + end + end + + describe 'when url does not exist' do + it 'responds with a 404' do + get :index, params: { keyword: "test404#{url.keyword}" } + expect(response.status).to eq(404) + end + + it 'renders 404 page regardless of format param' do + %i[html json xml php txt nil].each do |format| + get :index, params: { keyword: "test404#{url.keyword}", format: format } + expect(response.status).to eq(404) + end + end + end + end + + describe 'Click count /:keyword' do + describe 'user agent google' do + it 'does not count' do + @request.user_agent = "Googlebot/2.1" + get :index, params: { keyword: url.keyword } + new_url = Url.find(url.id) + expect(url.total_clicks).to eq(new_url.total_clicks) + end + end + + describe 'user agent chrome' do + it 'counts' do + @request.user_agent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" + get :index, params: { keyword: url.keyword } + new_url = Url.find(url.id) + expect(url.total_clicks).not_to eq(new_url.total_clicks) + end + end + end +end diff --git a/spec/controllers/redirect_spec.rb b/spec/controllers/redirect_spec.rb deleted file mode 100644 index 82365951..00000000 --- a/spec/controllers/redirect_spec.rb +++ /dev/null @@ -1,41 +0,0 @@ -require 'rails_helper' - -describe RedirectController do - let(:url) { FactoryGirl.create(:url) } - - describe 'GET /:keyword' do - describe 'url exists' do - it 'redirects back to the referring page' do - get :index, params: { keyword: url.keyword } - expect(response).to redirect_to url.url - end - end - describe 'url does not exist' do - it 'redirects back to the root path' do - get :index, params: {keyword: "5#{url.keyword}" } - expect(response).to redirect_to root_path - end - end - end - - describe 'Click count /:keyword' do - describe 'user agent google' do - it 'should not count' do - initialClicks = url.total_clicks - @request.user_agent = "Googlebot/2.1" - get :index, params: { keyword: url.keyword } - newURL = Url.find(url.id) - expect(url.total_clicks).to eq(newURL.total_clicks) - end - end - describe 'user agent chrome' do - it 'should count' do - initialClicks = url.total_clicks - @request.user_agent = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" - get :index, params: { keyword: url.keyword } - newURL = Url.find(url.id) - expect(url.total_clicks).not_to eq(newURL.total_clicks) - end - end - end -end diff --git a/spec/factories/factories.rb b/spec/factories/factories.rb index 257029bb..b6cac67b 100644 --- a/spec/factories/factories.rb +++ b/spec/factories/factories.rb @@ -1,36 +1,38 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :user do sequence(:uid) - admin false + admin { false } sequence(:display_name_loaded) { |n| "first_name#{n}" } sequence(:internet_id_loaded) { |n| "internet_id#{n}" } factory :admin do - admin true + admin { true } end end factory :audit do - item_type 'url' - item_id '1' - event 'create' - whodunnit { FactoryGirl.create(:user) } - object 'test_keyword' - whodunnit_email 'abc.def,com' - whodunnit_name 'Julia Child' + item_type { 'url' } + item_id { '1' } + event { 'create' } + whodunnit { FactoryBot.create(:user) } + object { 'test_keyword' } + whodunnit_email { 'abc.def,com' } + whodunnit_name { 'Julia Child' } end factory :url do - url 'http://google.com' + url { 'http://google.com' } sequence(:keyword) { |n| "keyword#{n}" } - group { FactoryGirl.create(:user).context_group } + group { FactoryBot.create(:user).context_group } end - factory :announcement, :class => Admin::Announcement do - title 'Whoa Nelly!' - body 'The Court is in Session, here comes the judge!' - start_delivering_at (DateTime.now - 30.days).strftime("%Y-%m-%d") - stop_delivering_at (DateTime.now + 30.days).strftime("%Y-%m-%d") + factory :announcement, class: 'Admin::Announcement' do + title { 'Whoa Nelly!' } + body { 'The Court is in Session, here comes the judge!' } + start_delivering_at { (DateTime.now - 30.days).strftime("%Y-%m-%d") } + stop_delivering_at { (DateTime.now + 30.days).strftime("%Y-%m-%d") } end factory :group do @@ -39,17 +41,22 @@ end factory :transfer_request do - from_user { FactoryGirl.create(:user) } - to_user { FactoryGirl.create(:user) } + from_user { FactoryBot.create(:user) } + to_user { FactoryBot.create(:user) } to_group { to_user.default_group } from_group { from_user.default_group } - urls { [FactoryGirl.create(:url, group: from_group)] } + urls { [FactoryBot.create(:url, group: from_group)] } end factory :frequently_asked_question do - header "Header" - question "Question" - answer "Answer" + header { "Header" } + question { "Question" } + answer { "Answer" } end end + +def create_url_for_user(user, factory_opts = nil) + url = FactoryBot.create(:url, factory_opts) + url.update(group: user.context_group) +end diff --git a/spec/features/admin/announcements_spec.rb b/spec/features/admin/announcements_spec.rb index a04dd77c..c8a62488 100644 --- a/spec/features/admin/announcements_spec.rb +++ b/spec/features/admin/announcements_spec.rb @@ -2,64 +2,63 @@ describe 'as a non-admin user visiting the admin page' do before do - @user = FactoryGirl.create(:user) - @announcement = FactoryGirl.create(:announcement) + @user = FactoryBot.create(:user) + @announcement = FactoryBot.create(:announcement) sign_in(@user) visit admin_announcements_path end - it 'should display an access violation' do + + it 'displays an access violation' do expect(page).to have_content 'You are not authorized to perform this action.' end - end - describe 'as a valid user' do before do - @user = FactoryGirl.create(:user) - @announcement = FactoryGirl.create(:announcement) + @user = FactoryBot.create(:user) + @announcement = FactoryBot.create(:announcement) sign_in(@user) visit urls_path end - it 'should display the announcement ' do + it 'displays the announcement' do expect(page).to have_content 'The Court is in Session' end - end - - describe 'as a valid admin user' do before do - @admin = FactoryGirl.create(:admin) + @admin = FactoryBot.create(:admin) sign_in(@admin) visit admin_announcements_path end - it 'should display announcement body' do + it 'displays announcement body' do expect(page).to have_content 'Message' end - it 'should display announcement start by date' do + it 'displays announcement start by date' do expect(page).to have_content 'Start delivering at' end - it 'should display announcement end by date' do + it 'displays announcement end by date' do expect(page).to have_content 'Stop delivering at' end + describe 'without an announcement' do - it 'should display invitation to add an announcement' do + it 'displays invitation to add an announcement' do expect(page).to have_content 'No Announcements. Click' end end + describe 'with an announcement' do before do - @announcement = FactoryGirl.create(:announcement) + @announcement = FactoryBot.create(:announcement) visit admin_announcements_path end - it 'should not display invitation to add an announcement' do - expect(page).to_not have_content 'No Announcements. Click' + + it 'does not display invitation to add an announcement' do + expect(page).not_to have_content 'No Announcements. Click' end end end diff --git a/spec/features/admin/audits_spec.rb b/spec/features/admin/audits_spec.rb index fc75e604..51976114 100644 --- a/spec/features/admin/audits_spec.rb +++ b/spec/features/admin/audits_spec.rb @@ -2,46 +2,45 @@ describe 'as a non-admin user' do before do - @user = FactoryGirl.create(:user) - @audit = FactoryGirl.create(:audit, whodunnit: @user.id) + @user = FactoryBot.create(:user) + @audit = FactoryBot.create(:audit, whodunnit: @user.id) sign_in(@user) visit admin_audits_path end - it 'should display an access violation' do + + it 'displays an access violation' do expect(page).to have_content 'You are not authorized to perform this action.' end - end describe 'as a valid admin user' do before do - @admin = FactoryGirl.create(:admin) + @admin = FactoryBot.create(:admin) sign_in(@admin) visit admin_audits_path end - it 'should display the audit title' do + it 'displays the audit title' do expect(page).to have_content 'Audit Log' end - it 'should display Audited Item col header' do + it 'displays Audited Item col header' do expect(page).to have_content 'Item' end - it 'should display Audited Action col header' do + it 'displays Audited Action col header' do expect(page).to have_content 'Last Action' end - it 'should display Whodunnit col header' do + it 'displays Whodunnit col header' do expect(page).to have_content 'Whodunnit' end - it 'should display When col header' do + it 'displays When col header' do expect(page).to have_content 'Change History' end - it 'should display When col header' do + it 'displays When col header' do expect(page).to have_content 'As Of' end - end diff --git a/spec/features/admin/csvs_spec.rb b/spec/features/admin/csvs_spec.rb index 3f29d1f1..b095e4a3 100644 --- a/spec/features/admin/csvs_spec.rb +++ b/spec/features/admin/csvs_spec.rb @@ -3,38 +3,38 @@ describe 'admins getting csv of clicks for url(s) clicked yesterday and two days ago' do let(:keyword) { 'testkeyword' } let(:url) { 'http://www.google.com' } - let(:created_at) { Time.now - 1.day } + let(:created_at) { Time.zone.now - 1.day } let(:keyword2) { 'testkeyword2' } let(:url2) { 'http://www.google2.com' } - let(:created_at2) { Time.now - 1.day } + let(:created_at2) { Time.zone.now - 1.day } before do - @admin = FactoryGirl.create(:admin) - @user = FactoryGirl.create(:user) + @admin = FactoryBot.create(:admin) + @user = FactoryBot.create(:user) sign_in(@admin) # tests should use user urls not admins to tst that the urls are viewable by admin # though not necessarily owned by admin - @url = FactoryGirl.create( - :url, - group: @user.context_group, - keyword: keyword, - url: url, - created_at: created_at + @url = FactoryBot.create( + :url, + group: @user.context_group, + keyword: keyword, + url: url, + created_at: created_at ) - @url2 = FactoryGirl.create( - :url, - group: @user.context_group, - keyword: keyword2, - url: url2, - created_at: created_at2 + @url2 = FactoryBot.create( + :url, + group: @user.context_group, + keyword: keyword2, + url: url2, + created_at: created_at2 ) # add 10 clicks to yesterday for first url 10.times do @url.clicks << Click.create( - country_code: 'US', - created_at: Time.now - 1.day + country_code: 'US', + created_at: Time.zone.now - 1.day ) @url.total_clicks += 1 @url.save @@ -42,8 +42,8 @@ # add 5 clicks to yesterday for second url 5.times do @url2.clicks << Click.create( - country_code: 'US', - created_at: Time.now - 2.day + country_code: 'US', + created_at: Time.zone.now - 2.days ) @url2.total_clicks += 1 @url2.save @@ -58,16 +58,20 @@ @header_row = @csv.shift @data_row = @csv.shift end - it 'should have two rows a header and data for one url' do + + it 'has two rows a header and data for one url' do expect(CSV.parse(Url.to_csv('2', 'days', @urls)).size).to match(2) end - it 'should have column name url in first cell, first row' do + + it 'has column name url in first cell, first row' do expect(@header_row[0]).to match('url') end - it 'should have column name keyword in second cell, first row' do + + it 'has column name keyword in second cell, first row' do expect(@header_row[1]).to match('keyword') end end + describe 'for 2 urls, two days' do before do # get yesterday's and two days ago csv @@ -77,13 +81,16 @@ @yesterday = @csv.shift @two_days_ago = @csv.shift end - it 'should have three rows a header and 2 riws data for 2 url' do + + it 'has three rows a header and 2 riws data for 2 url' do expect(CSV.parse(Url.to_csv('2', 'days', @urls)).size).to match(3) end - it 'should have column name url in first cell, first row' do + + it 'has column name url in first cell, first row' do expect(@header_row[0]).to match('url') end - it 'should have column name keyword in second cell, first row' do + + it 'has column name keyword in second cell, first row' do expect(@header_row[1]).to match('keyword') end end diff --git a/spec/features/admin/transfer_request_spec.rb b/spec/features/admin/transfer_request_spec.rb index 259f0802..c087aed7 100644 --- a/spec/features/admin/transfer_request_spec.rb +++ b/spec/features/admin/transfer_request_spec.rb @@ -2,76 +2,83 @@ describe 'admin urls index page' do before do - @admin = FactoryGirl.create(:admin) + @admin = FactoryBot.create(:admin) sign_in(@admin) end describe 'creating a transfer request', js: true do before do visit admin_urls_path - wait_for_ajax end describe 'with no urls' do describe 'the transfer button' do - it 'should be disabled' do - wait_for_ajax - expect(page.find('.table-options')[:class]).to( - have_content('disabled') - ) + # FIXME: flakey test. Adding retry for now. + it 'is disabled', retry: 3 do + expect(page).to have_css('.table-options.disabled') end end end + describe 'with urls' do before do - @user = FactoryGirl.create(:user) - @users_url = FactoryGirl.create(:url, group: @user.context_group) - @admins_url = FactoryGirl.create(:url, group: @admin.context_group) - FactoryGirl.create(:url, group: @user.context_group) - FactoryGirl.create(:url, group: @user.context_group) + @user = FactoryBot.create(:user) + @users_url = FactoryBot.create(:url, group: @user.context_group) + @admins_url = FactoryBot.create(:url, group: @admin.context_group) + FactoryBot.create(:url, group: @user.context_group) + FactoryBot.create(:url, group: @user.context_group) visit admin_urls_path - wait_for_ajax end + describe 'as an admin' do describe ' and not in the group of of the url' do before do find("#url-#{@users_url.id} > .select-checkbox").click page.find('.table-options').click page.find('.js-transfer-urls').click - wait_for_ajax - @to_user = FactoryGirl.create(:user) - first('input#transfer_request_to_group', visible: false).set @to_user.uid + @to_user = FactoryBot.create(:user) + + # Use JS Make hidden input visible for testing + # as a workaround for the option "visible: false" + # which doesn't seem to work on this test + js_make_all_inputs_visible + first('#transfer_request_to_group').set @to_user.uid find('#new_transfer_request input[type="submit"]').click click_button 'Confirm' - wait_for_ajax + sleep 0.1 end - it 'should have transfered' do - expect(TransferRequest.find_by(to_group: @to_user.context_group_id).status).to be == 'approved' + + it 'has transfered' do + # check that the modal has been dismissed + expect(page).to have_no_css('#new_transfer_request') + transfer = TransferRequest.find_by(to_group: @to_user.context_group_id) + expect(transfer.status).to eql('approved') end end + describe 'and in the group of the url' do before do find("#url-#{@admins_url.id} > .select-checkbox").click page.find('.table-options').click page.find('.js-transfer-urls').click - wait_for_ajax - @to_user = FactoryGirl.create(:user) - first('input#transfer_request_to_group', visible: false).set @to_user.uid + + @to_user = FactoryBot.create(:user) + js_make_all_inputs_visible + first('input#transfer_request_to_group').set @to_user.uid find('#new_transfer_request input[type="submit"]').click click_button 'Confirm' - wait_for_ajax end - it 'should not have transferred' do + + it 'does not have transferred' do expect(@admin.context_group.urls.count).to be == 1 end end end + describe 'with no urls selected' do describe 'the transfer button' do - it 'should be disabled' do - expect(page.find('.table-options')[:class]).to( - have_content('disabled') - ) + it 'is disabled' do + expect(page).to have_css('.table-options.disabled') end end end @@ -80,10 +87,11 @@ before do find("#url-#{@users_url.id} > .select-checkbox").click end + describe 'the transfer button' do - it 'should be enabled' do - expect(page.find('.table-options')[:class]).to_not( - have_content('disabled') + it 'is enabled' do + expect(page.find('.table-options')[:class]).not_to( + have_content('disabled') ) end end @@ -92,63 +100,77 @@ before do page.find('.table-options').click page.find('.js-transfer-urls').click - wait_for_ajax end - it 'should display the modal' do - expect(page).to have_selector('#index-modal', visible: true) + it 'displays the modal' do + expect(page).to have_selector('#index-modal') end describe 'filling out the form' do describe 'with valid information' do before do - @other_user = FactoryGirl.create(:user) - first('input#transfer_request_to_group', visible: false).set @other_user.uid + @other_user = FactoryBot.create(:user) + js_make_all_inputs_visible + first('input#transfer_request_to_group').set @other_user.uid end - it 'should not create a transfer request' do + + it 'does not create a transfer request' do expect do find('#new_transfer_request input[type="submit"]').click - wait_for_ajax end.to change(TransferRequest, :count).by(0) end + describe 'user does not exist' do let(:new_uid) { 'notauser123456' } + before do - first('input#transfer_request_to_group', visible: false).set new_uid + js_make_all_inputs_visible + first('input#transfer_request_to_group').set new_uid end - it 'should create a new user' do + + it 'creates a new user' do expect do find('#new_transfer_request input[type="submit"]').click click_button 'Confirm' - wait_for_ajax + + # check that the modal has been dismissed + expect(page).to have_no_css('#new_transfer_request') end.to change(User, :count).by(1) end - it 'should create an approved transfer request to the new user' do - find('#new_transfer_request input[type="submit"]').click - click_button 'Confirm' - wait_for_ajax - user = User.find_by(uid: new_uid) - expect(TransferRequest.find_by(to_group: user.context_group_id).status).to be == 'approved' - expect(user.context_group.id).to be == TransferRequest.find_by(to_group: user.context_group_id).to_group_id + + it 'creates an approved transfer request to the new user' do + find('#new_transfer_request input[type="submit"]').click + click_button 'Confirm' + + # check that the modal has been dismissed + expect(page).to have_no_css('#new_transfer_request') + user = User.find_by(uid: new_uid) + + transfer = TransferRequest.find_by(to_group: user.context_group_id) + expect(transfer.status).to eql('approved') + expect(user.context_group.id).to eql(transfer.to_group_id) end end end + describe 'with invalid information' do let(:new_uid) { '' } + describe 'uid is blank' do before do - first('input#transfer_request_to_group', visible: false).set new_uid + js_make_all_inputs_visible + first('input#transfer_request_to_group').set new_uid end - it 'should display an error' do + + it 'displays an error' do find('#new_transfer_request input[type="submit"]').click click_button "Confirm" - wait_for_ajax expect(page).to have_content 'To group must exist' end - it 'should not create a transfer request' do + + it 'does not create a transfer request' do expect do find('#new_transfer_request input[type="submit"]').click - wait_for_ajax end.to change(TransferRequest, :count).by(0) end end diff --git a/spec/features/admin/urls_spec.rb b/spec/features/admin/urls_spec.rb index 588b0c4f..e5e6ac12 100644 --- a/spec/features/admin/urls_spec.rb +++ b/spec/features/admin/urls_spec.rb @@ -2,40 +2,40 @@ describe 'as a non-admin user' do before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) visit admin_urls_path end - it 'should display an access violation' do + it 'displays an access violation' do expect(page).to have_content 'You are not authorized to perform this action.' end - end describe 'as a valid admin user' do before do - @admin = FactoryGirl.create(:admin) + @admin = FactoryBot.create(:admin) sign_in(@admin) end describe 'visiting admin url index' do before { visit admin_urls_path } + it 'display the URL title' do expect(page).to have_content 'URLs' end - it 'should have the Owner field' do + it 'has the Owner field' do expect(page).to have_content 'Owner' end describe 'with an existing URL', js: true do before do - @url = FactoryGirl.create(:url) + @url = FactoryBot.create(:url) visit admin_urls_path end - it 'should display the actions dropdown button' do + it 'displays the actions dropdown button' do expect(page).to have_selector('.dropdown .actions-dropdown-button') end @@ -44,51 +44,45 @@ let(:new_keyword) { 'face' } describe 'when editing', js: true do - before { + before do find('.dropdown .actions-dropdown-button').click find('.dropdown-menu .edit-url').click - } + end describe 'with new valid content' do - it 'should update the url in the db' do + it 'updates the url in the db' do + expect(page).to have_css('#url_url') find('#url_url').set new_url find('.js-url-submit').click wait_for_ajax expect(@url.reload.url).to eq(new_url) end - it 'should update the keyword in the db' do + + it 'updates the keyword in the db' do find('#url_keyword').set new_keyword find('.js-url-submit').click wait_for_ajax expect(@url.reload.keyword).to eq(new_keyword) end end + describe 'with invalid content' do - describe '[keyword]' do - describe 'already taken' do - before do - @other_url = FactoryGirl.create(:url) - find('#url_keyword').set @other_url.keyword - end - it 'should not save upon clicking Create' do - expect do - find('.js-url-submit').click - wait_for_ajax - end.to change(Url, :count).by(0) - end - it 'should display an error' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to have_content('taken') - end - end + it 'displays an error and does not save upon clicking Create if keyword is already taken' do + @other_url = FactoryBot.create(:url) + expect(page).to have_selector('#url_keyword') + find('#url_keyword').set @other_url.keyword + + expect do + find('.js-url-submit').click + expect(page).to have_content('taken') + end.to change(Url, :count).by(0) end end end describe 'when deleting existing url', js: true do describe 'clicking delete' do - it 'should delete the url' do + it 'deletes the url' do expect do find('.dropdown .actions-dropdown-button').click find('.dropdown-menu .delete-url').click diff --git a/spec/features/admin_members_spec.rb b/spec/features/admin_members_spec.rb index 395c439d..b4ca9317 100644 --- a/spec/features/admin_members_spec.rb +++ b/spec/features/admin_members_spec.rb @@ -1,73 +1,85 @@ require 'rails_helper' +def wait_for_admin_page_to_load + expect(page).to have_content('Add an Admin') +end + describe 'admin members index page' do before do - @user = FactoryGirl.create(:user, admin: true, uid: 'wozniak') + @user = FactoryBot.create(:user, admin: true, uid: :test_admin_uid) sign_in(@user) visit admin_members_path(@user) end describe 'visiting the group membership page' do - let(:user) { User.where(uid: 'wozniak').first } - describe 'page content' do - it 'should display the admin member internet_id' do - expect(page).to have_content user.internet_id - end - it 'should display the admin member display name' do - expect(page).to have_content user.display_name - end + let(:user) { User.where(uid: :test_admin_uid).first } + + it 'displays the admin member internet_id' do + expect(page).to have_content user.internet_id + end + + it 'displays the admin member display name' do + expect(page).to have_content user.display_name end end describe 'creating and deleting a admin member', js: true do - describe 'to an existing group of admins' do - let(:group) { FactoryGirl.create(:group) } - it 'add and then set the new member admin flag to true' do - find('#uid', visible: false).set 'andersen' - click_button 'Add' - click_button 'Confirm' - wait_for_ajax - visit admin_members_path(@user) - expect(User.where(uid: 'andersen', admin: true)).to exist - end - describe 'clicking delete' do - it 'should first add a new member and then delete it with notification' do - find('#uid', visible: false).set 'andersen' - click_button 'Add' - click_button 'Confirm' - wait_for_ajax - visit admin_members_path(@user) - page.all(:css, '.delete-admin-member')[1].click - click_button 'Confirm' - wait_for_ajax - visit admin_members_path(@user) - expect(User.where(uid: 'andersen', admin: true)).not_to exist - expect(page).to have_content '(testinternetid) has been removed.' - end - end - describe 'clicking delete on oneself' do - it 'should delete oneself and not allow deleted user to view admin pages' do - visit admin_members_path(@user) - page.all(:css, '.delete-admin-member')[0].click - click_button 'Confirm' - wait_for_ajax - visit admin_members_path(@user) - expect(User.where(uid: 'wozniak', admin: true)).not_to exist - expect(page).to have_content 'You are not authorized to perform this action. ' - end + before do + js_make_all_inputs_visible + end + + it 'adds admin a new admin to an existing group of admins' do + find('#uid', visible: false).set :new_admin_uid + click_button 'Add' + click_button 'Confirm' + + visit admin_members_path(@user) + wait_for_admin_page_to_load + + # DB should be updated + expect(User.where(uid: :new_admin_uid, admin: true)).to exist + + # Admin table should have two entries now. + # one for :test_admin_uid and :new_admin_uid + within 'table' do + expect(page).to have_selector 'tbody > tr', count: 2 end end + + it 'deletes an admin and displays a notification' do + find('#uid', visible: false).set :new_admin_uid + click_button 'Add' + click_button 'Confirm' + + visit admin_members_path(@user) + wait_for_admin_page_to_load + page.all(:css, '.delete-admin-member')[1].click + click_button 'Confirm' + expect(page).to have_content 'has been removed.' + expect(User.where(uid: :new_admin_uid, admin: true)).not_to exist + end + + it 'when removing oneself from the admins, one should not view the admin pages' do + visit admin_members_path(@user) + wait_for_admin_page_to_load + page.all(:css, '.delete-admin-member')[0].click + click_button 'Confirm' + + visit admin_members_path(@user) + expect(User.where(uid: :test_admin_uid, admin: true)).not_to exist + expect(page).to have_content 'not authorized' + end end end + describe 'visiting the admin member list as a non-admin' do before do - bad_user = FactoryGirl.create(:user, uid: 'jones') + bad_user = FactoryBot.create(:user, uid: :non_admin_user) sign_in(bad_user) visit admin_members_path(bad_user) end - describe 'page content' do - it 'should display the authorization error' do - expect(page).to have_content 'You are not authorized to perform this action.' - end + + it 'displays the authorization error' do + expect(page).to have_content 'not authorized' end end diff --git a/spec/features/copy_short_url.rb b/spec/features/copy_short_url.rb index 3c1b0205..eb146b70 100644 --- a/spec/features/copy_short_url.rb +++ b/spec/features/copy_short_url.rb @@ -2,13 +2,13 @@ describe 'copy url button ' do before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) end describe 'on the urls', js: true do before do - @new_url = FactoryGirl.create(:url, group: @user.context_group) + @new_url = FactoryBot.create(:url, group: @user.context_group) end describe 'index page', js: true do @@ -17,7 +17,7 @@ end describe 'the copy button' do - it 'should be present' do + it 'is present' do expect(page).to have_selector('.clipboard-btn') end end @@ -25,12 +25,12 @@ describe 'details page', js: true do before do - @new_url = FactoryGirl.create(:url, group: @user.context_group) + @new_url = FactoryBot.create(:url, group: @user.context_group) visit url_path(@new_url.keyword) end describe 'the copy button' do - it 'should be present' do + it 'is present' do expect(page).to have_selector('.clipboard-btn') end end diff --git a/spec/features/csvs_spec.rb b/spec/features/csvs_spec.rb index 1b62d0c1..7af9fbf0 100644 --- a/spec/features/csvs_spec.rb +++ b/spec/features/csvs_spec.rb @@ -3,35 +3,35 @@ describe 'getting csv of clicks for url(s) clicked yesterday and two days ago' do let(:keyword) { 'testkeyword' } let(:url) { 'http://www.google.com' } - let(:created_at) { Time.now - 1.day } + let(:created_at) { Time.zone.now - 1.day } let(:keyword2) { 'testkeyword2' } let(:url2) { 'http://www.google2.com' } - let(:created_at2) { Time.now - 1.day } + let(:created_at2) { Time.zone.now - 1.day } before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) - @url = FactoryGirl.create( - :url, - group: @user.context_group, - keyword: keyword, - url: url, - created_at: created_at + @url = FactoryBot.create( + :url, + group: @user.context_group, + keyword: keyword, + url: url, + created_at: created_at ) - @url2 = FactoryGirl.create( - :url, - group: @user.context_group, - keyword: keyword2, - url: url2, - created_at: created_at2 + @url2 = FactoryBot.create( + :url, + group: @user.context_group, + keyword: keyword2, + url: url2, + created_at: created_at2 ) # add 10 clicks to yesterday for first url 10.times do @url.clicks << Click.create( - country_code: 'US', - created_at: Time.now - 1.day + country_code: 'US', + created_at: Time.zone.now - 1.day ) @url.total_clicks += 1 @url.save @@ -39,8 +39,8 @@ # add 5 clicks to yesterday for second url 5.times do @url2.clicks << Click.create( - country_code: 'US', - created_at: Time.now - 2.day + country_code: 'US', + created_at: Time.zone.now - 2.days ) @url2.total_clicks += 1 @url2.save @@ -55,16 +55,20 @@ @header_row = @csv.shift @data_row = @csv.shift end - it 'should have two rows a header and data for one url' do + + it 'has two rows a header and data for one url' do expect(CSV.parse(Url.to_csv('2', 'days', @urls)).size).to match(2) end - it 'should have column name url in first cell, first row' do + + it 'has column name url in first cell, first row' do expect(@header_row[0]).to match('url') end - it 'should have column name keyword in second cell, first row' do + + it 'has column name keyword in second cell, first row' do expect(@header_row[1]).to match('keyword') end end + describe 'for 2 urls, two days' do before do # get yesterday's and two days ago csv @@ -74,13 +78,16 @@ @yesterday = @csv.shift @two_days_ago = @csv.shift end - it 'should have three rows a header and 2 riws data for 2 url' do + + it 'has three rows a header and 2 riws data for 2 url' do expect(CSV.parse(Url.to_csv('2', 'days', @urls)).size).to match(3) end - it 'should have column name url in first cell, first row' do + + it 'has column name url in first cell, first row' do expect(@header_row[0]).to match('url') end - it 'should have column name keyword in second cell, first row' do + + it 'has column name keyword in second cell, first row' do expect(@header_row[1]).to match('keyword') end end diff --git a/spec/features/faq_spec.rb b/spec/features/faq_spec.rb index 60c8e6b4..39281973 100644 --- a/spec/features/faq_spec.rb +++ b/spec/features/faq_spec.rb @@ -2,31 +2,35 @@ describe 'visit the faq page ' do before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) end describe 'index page', js: true do before do - FactoryGirl.create(:frequently_asked_question) + FactoryBot.create(:frequently_asked_question) visit faq_path end - it 'should give you the title of the page' do + + it 'gives you the title of the page' do expect(page).to have_content 'Z Frequently Asked Questions' end - it 'should have a header for a group of faqs' do + + it 'has a header for a group of faqs' do expect(page).to have_content 'Header' end - it 'should have a question' do + + it 'has a question' do expect(page).to have_content 'Question' end - it 'should not have an answer displayed before the question is clicked on' do - expect(page).to_not have_content 'Answer' + + it 'does not have an answer displayed before the question is clicked on' do + expect(page).not_to have_content 'Answer' end - it 'should have an answer when a question is clicked on' do + + it 'has an answer when a question is clicked on' do click_link('Question') expect(page).to have_content 'Answer' end - end end diff --git a/spec/features/group_membership_spec.rb b/spec/features/group_membership_spec.rb index 8be492df..24e0041d 100644 --- a/spec/features/group_membership_spec.rb +++ b/spec/features/group_membership_spec.rb @@ -1,31 +1,37 @@ -require 'rails_helper' +# frozen_string_literal: true +require 'rails_helper' describe 'groups members index page' do before do - @user = FactoryGirl.create(:user, uid: 'wozniak') + @user = FactoryBot.create(:user, uid: 'wozniak') end describe 'visiting the group membership page' do - let(:group) { FactoryGirl.create(:group) } - let(:user) { User.where(:uid => @user.uid).first } + let(:group) { FactoryBot.create(:group) } + let(:user) { User.where(uid: @user.uid).first } + before do group.users << @user group.save sign_in(@user) visit group_members_path(group) end + describe 'page content' do - it 'should display the group name' do + it 'displays the group name' do expect(page).to have_content group.name end - it 'should display the group member full name' do + + it 'displays the group member full name' do expect(page).to have_content user.display_name end - it 'should display the group member email' do + + it 'displays the group member email' do expect(page).to have_content user.email end - it 'should display a delete button' do + + it 'displays a delete button' do expect(page).to have_content 'Remove' end end @@ -33,25 +39,28 @@ describe 'creating and deleting a group member', js: true do describe 'to an existing group' do - let(:group) { FactoryGirl.create(:group) } + let(:group) { FactoryBot.create(:group) } + before do group.users << @user group.save sign_in(@user) visit group_members_path(group) - # p page.body end - it 'adding should increase the user count of the group by 1' do + + it 'adding should increase the user count of the group by 1', retry: 3 do expect do + js_make_all_inputs_visible + fill_in('Add a new member', with: 'test-user') find("#uid", visible: false).set '5scyi59j8' click_button 'Add' click_button 'Confirm' wait_for_ajax group.reload end.to change(group.users, :count).by(1) - end - it 'clicking delete decrease the user count by one' do + + it 'clicking delete decrease the user count by one', retry: 3 do expect do find('.delete-group-member').click click_button 'Confirm' @@ -59,6 +68,21 @@ end.to change(group.users, :count).by(-1) end + it 'prevents blank submissions' do + # by default the button should be disabled + # until a value is entered + expect(page).to have_button('Add member', disabled: true) + + # enter a value + fill_in 'Add a new member to this collection', with: 'johnsojr' + # the button should now be enabled + expect(page).to have_button('Add member', disabled: false) + + # remove the text + fill_in 'Add a new member to this collection', with: '' + # the button should now be disabled again + expect(page).to have_button('Add member', disabled: true) + end end end end diff --git a/spec/features/group_to_urls_spec.rb b/spec/features/group_to_urls_spec.rb index 60dd4f34..a36b2c94 100644 --- a/spec/features/group_to_urls_spec.rb +++ b/spec/features/group_to_urls_spec.rb @@ -1,10 +1,11 @@ require 'rails_helper' describe 'with a group that has URLs', js: true do - let(:group) { FactoryGirl.create(:group) } - let(:other_group) { FactoryGirl.create(:group) } - let(:user) { FactoryGirl.create(:user) } - let(:url) { FactoryGirl.create(:url) } + let(:group) { FactoryBot.create(:group) } + let(:other_group) { FactoryBot.create(:group) } + let(:user) { FactoryBot.create(:user) } + let(:url) { FactoryBot.create(:url) } + before do user.groups << group user.groups << other_group @@ -20,23 +21,26 @@ click_link(group.name) end - it 'should pre-select the collection' do + it 'pre-selects the collection' do expect(page).to have_select('collection-filter', visible: false, selected: group.name) end - it 'should display the URL in the collection' do + + it 'displays the URL in the collection' do expect(page).to have_content(url.keyword) end end + describe 'when the group does not have URLs' do before do click_link(other_group.name) end - it 'should pre-select the collection' do + it 'pre-selects the collection' do expect(page).to have_select('collection-filter', visible: false, selected: other_group.name) end - it 'should not display the URL' do - expect(page).to_not have_content(url.keyword) + + it 'does not display the URL' do + expect(page).not_to have_content(url.keyword) end end end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 8e669194..902ae1dc 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -2,7 +2,7 @@ describe 'groups index page', js: true do before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) wait_for_ajax end @@ -10,6 +10,7 @@ describe 'creating a new group', js: true do let(:name) { 'My First Group' } let(:description) { 'first group of urls' } + before do visit groups_path find('.add-new-group').click @@ -17,24 +18,28 @@ find('#group_name').set name find('#group_description').set description end + describe 'with valid information' do describe 'when both fields are filled in' do - it 'should save upon clicking Create' do + it 'saves upon clicking Create' do expect do find('.js-group-submit').click wait_for_ajax end.to change(Group, :count).by(1) end - it 'should add the user to the group' do + + it 'adds the user to the group' do expect do find('.js-group-submit').click wait_for_ajax end.to change(GroupsUser, :count).by(1) end end + describe 'when the description is blank' do before { find('#group_description').set '' } - it 'should save upon clicking Create' do + + it 'saves upon clicking Create' do expect do find('.js-group-submit').click wait_for_ajax @@ -42,17 +47,20 @@ end end end + describe 'with invalid information' do describe '[name]' do describe 'name is blank' do before { find('#group_name').set '' } - it 'should not save upon clicking Create' do + + it 'does not save upon clicking Create' do expect do find('.js-group-submit').click wait_for_ajax end.to change(Group, :count).by(0) end - it 'should display an error' do + + it 'displays an error' do find('.js-group-submit').click wait_for_ajax expect(page).to have_content('Name can\'t be blank') @@ -65,7 +73,8 @@ describe 'with an existing group', js: true do let(:new_name) { 'My Second Group' } let(:new_description) { 'second group of urls' } - let(:group) { FactoryGirl.create(:group) } + let(:group) { FactoryBot.create(:group) } + before do group.users << @user group.save @@ -76,17 +85,20 @@ end describe 'page content' do - it 'should display the group name' do + it 'displays the group name' do expect(page).to have_content group.name end - it 'should display the group description' do + + it 'displays the group description' do expect(page).to have_content group.description end - it 'should display an edit button' do + + it 'displays an edit button' do find('.js-group-actions-dropdown').click expect(page).to have_content 'Edit' end - it 'should display a delete button' do + + it 'displays a delete button' do find('.js-group-actions-dropdown').click expect(page).to have_content 'Delete' end @@ -99,7 +111,7 @@ end describe 'with new valid content' do - it 'should update the group name in the db' do + it 'updates the group name in the db' do find('#group_name').set new_name find('.js-group-submit').click wait_for_ajax @@ -107,7 +119,8 @@ find('.edit-group').click expect(find('#group_name')['value']).to eq(new_name) end - it 'should update the group description in the db' do + + it 'updates the group description in the db' do find('#group_description').set new_description find('.js-group-submit').click wait_for_ajax @@ -121,8 +134,9 @@ describe 'deleting an existing group', js: true do describe 'clicking delete' do describe 'on a group with urls' do - before { group.urls << FactoryGirl.create(:url) } - it 'should not delete the group' do + before { group.urls << FactoryBot.create(:url) } + + it 'does not delete the group' do expect do find('.js-group-actions-dropdown').click find('.delete-group').click @@ -131,8 +145,9 @@ end.to change(Group, :count).by(0) end end + describe 'on a group without urls' do - it 'should delete the group' do + it 'deletes the group' do expect do find('.js-group-actions-dropdown').click find('.delete-group').click @@ -147,15 +162,14 @@ describe 'when attempting to edit someone elses group' do before do - unauthed_group = FactoryGirl.create(:group) + unauthed_group = FactoryBot.create(:group) visit edit_group_path(unauthed_group) end + describe 'page content' do - it 'should display the not authorized message' do + it 'displays the not authorized message' do expect(page).to have_content 'You are not authorized to perform this action.' end end end - - end diff --git a/spec/features/layout_spec.rb b/spec/features/layout_spec.rb index 5a8c76b3..71748f07 100644 --- a/spec/features/layout_spec.rb +++ b/spec/features/layout_spec.rb @@ -1,21 +1,25 @@ require 'rails_helper' describe 'the layout' do - let(:user) { FactoryGirl.create(:user) } + let(:user) { FactoryBot.create(:user) } + describe 'not signed in' do before { visit '/' } - it 'should have a sign in link' do + it 'has a sign in link' do expect(page).to have_link 'Sign In' end - it 'should not have a sign out link' do - expect(page).to_not have_link 'Sign Out' + + it 'does not have a sign out link' do + expect(page).not_to have_link 'Sign Out' end - it 'should not have a URLs link' do - expect(page).to_not have_link 'URLs' + + it 'does not have a URLs link' do + expect(page).not_to have_link 'URLs' end - it 'should not have a Groups link' do - expect(page).to_not have_link 'Groups' + + it 'does not have a Groups link' do + expect(page).not_to have_link 'Groups' end end @@ -25,17 +29,19 @@ visit '/' end - it 'should have a sign out link' do + it 'has a sign out link' do expect(page).to have_link 'Sign Out' end - it 'should have a URLs link' do + + it 'has a URLs link' do expect(page).to have_link 'My Z-Links' end - it 'should have a Collections link' do + + it 'has a Collections link' do expect(page).to have_link 'Collections' end - it 'should have a Whats new link' do + it 'has a Whats new link' do click_link 'Help' expect(page).to have_link "What's New in Z" end diff --git a/spec/features/move_group_spec.rb b/spec/features/move_group_spec.rb index f5fc1db6..91785503 100644 --- a/spec/features/move_group_spec.rb +++ b/spec/features/move_group_spec.rb @@ -1,93 +1,74 @@ require 'rails_helper' +def expect_urls_page_to_finish_loading + expect(page).to have_content('Bulk Actions') + expect(page).to have_no_content('Processing') +end + describe 'moving urls to a group', js: true do before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) - - @other_group = FactoryGirl.create(:group) + @other_group = FactoryBot.create(:group) @user.groups << @other_group end - describe 'on the urls index page' do - before do + describe 'accessing html endpoints directly' do + it 'sends direct html visits to move_to_group/new to not found page' do + # dont give a 500 error for a missing template + visit new_move_to_group_path + expect(page).to have_content('Not Found') + end + end + + describe 'page with no urls' do + it 'has a disabled bulk action button' do visit urls_path - wait_for_ajax + expect_urls_page_to_finish_loading + + expect(page).to have_css('.table-options.disabled') end + end - describe 'with extra groups' do - before do - visit urls_path - wait_for_ajax - end + describe 'page with urls' do + before do + @url = FactoryBot.create(:url, group: @user.context_group) + visit urls_path + expect_urls_page_to_finish_loading + end - describe 'without urls' do - describe 'the table bulk actions button' do - it 'should be disabled' do - expect(page.find('.table-options')[:class]).to( - have_content('disabled') - ) - end - end - end + it 'disables bulk action button when no urls are selected' do + expect(page).to have_css('.table-options.disabled') + end - describe 'with urls' do - before do - @url = FactoryGirl.create(:url, group: @user.context_group) - visit urls_path - end + it 'enables bulk actions button when a url is selected' do + find("#url-#{@url.id} .select-checkbox").click - describe 'none selected' do - describe 'the table buld actions button' do - it 'should be disabled' do - expect(page.find('.table-options')[:class]).to( - have_content('disabled') - ) - end - end - end + expect(page).to have_css('.table-options') + expect(page).to have_no_css('.table-options.disabled') + end - describe 'selected' do - before do - find("#url-#{@url.id} .select-checkbox").click - end + it 'displays the modal clicking the "move group"' do + find("#url-#{@url.id} .select-checkbox").click + find('.table-options').click + click_link 'Move to a different collection' - describe 'the table bulk actions button' do - it 'should be enabled' do - expect(page.find('.table-options')[:class]).to_not( - have_content('disabled') - ) - end - end + expect(page).to have_selector('#index-modal') + end - describe 'clicking the move group button' do - before { - find('.table-options').click - click_link 'Move to a different collection' - } - it 'should display the modal' do - expect(page).to have_selector('#index-modal', visible: true) - end + it 'moves the url immediately upon confirming' do + find("#url-#{@url.id} .select-checkbox").click + find('.table-options').click + click_link 'Move to a different collection' + find('.js-move-group-group button').click + find('.dropdown-menu.open li', text: @other_group.name).click - describe 'filling out the form' do - describe 'with valid information' do - before do - find('.js-move-group-group button').click - find('.dropdown-menu.open li', text: @other_group.name).click - end - it 'should move url immediately' do - expect do - find('#move_group input[type="submit"]').click - click_button 'Confirm' - wait_for_ajax - @url.reload - end.to change(@url, :group_id).to(@other_group.id) - end - end - end - end - end - end + expect do + find('#move_group input[type="submit"]').click + click_button 'Confirm' + wait_for_ajax + @url.reload + end.to change(@url, :group_id).to(@other_group.id) end end end diff --git a/spec/features/not_found_spec.rb b/spec/features/not_found_spec.rb new file mode 100644 index 00000000..6f42fa8d --- /dev/null +++ b/spec/features/not_found_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Not Found' do + it 'shows Not Found for a url that does not exist' do + visit '/does_not_exist' + expect(page).to have_content('Not Found') + end + + it 'shows Not Found if url has a bad encoding in the path' do + visit '/%c0' + expect(page).to have_content('Not Found') + end + + it 'shows Not Found if query string is malformed', js: true do + # This is hard to test with RackTest, so using + # js: true to use a different test driver + visit '/someplace?alsdkjflakjdf%$$$)$%=' + expect(page).to have_content('Not Found') + end +end diff --git a/spec/features/root_path_spec.rb b/spec/features/root_path_spec.rb index c5c6befe..083de19d 100644 --- a/spec/features/root_path_spec.rb +++ b/spec/features/root_path_spec.rb @@ -1,14 +1,16 @@ require 'rails_helper' describe 'Visiting root' do - let(:user) { FactoryGirl.create(:user) } + let(:user) { FactoryBot.create(:user) } + describe 'not signed in' do before { visit '/' } - it 'should say Welcome' do + it 'says Welcome' do expect(page).to have_content 'Welcome' end - it 'should display Login to Z button' do + + it 'displays Login to Z button' do expect(page).to have_content 'Sign In to Z' end end @@ -19,11 +21,12 @@ visit '/' end - it 'should direct you to the home page' do + it 'directs you to the home page' do expect(page).to have_content 'z.umn.edu' end + it 'not display Login to Z button' do - expect(page).to_not have_content 'Login to Z' + expect(page).not_to have_content 'Login to Z' end end end diff --git a/spec/features/transfer_request_spec.rb b/spec/features/transfer_request_spec.rb index ddc01be9..25e514bd 100644 --- a/spec/features/transfer_request_spec.rb +++ b/spec/features/transfer_request_spec.rb @@ -1,77 +1,77 @@ require 'rails_helper' +def wait_for_urls_page_load + expect(page).to have_content("Bulk Actions") + expect(page).to have_no_content("Processing") +end + +def wait_for_modal_to_load + expect(page).to have_css("#new_transfer_request") +end + +def wait_for_modal_to_dismiss + expect(page).to have_no_css("#new_transfer_request") +end + describe 'creating a transfer request', js: true do before do - @user = FactoryGirl.create(:user) + @user = FactoryBot.create(:user) sign_in(@user) end - describe 'on the urls index page' do - before do + describe 'the urls index page' do + it 'has a disabled bulk action button if there are no urls', retry: 3 do visit urls_path - wait_for_ajax + expect(page).to have_css('.table-options.disabled') end - describe 'with no urls' do - describe 'the bulk actions button ' do - it 'should be disabled' do - expect(page.find('.table-options')[:class]).to( - have_content('disabled') - ) - end - end - end describe 'with urls' do before do - @selected_url = FactoryGirl.create(:url, group: @user.context_group) - FactoryGirl.create(:url, group: @user.context_group) - FactoryGirl.create(:url, group: @user.context_group) - visit urls_path - wait_for_ajax + @selected_url = FactoryBot.create(:url, group: @user.context_group) + FactoryBot.create(:url, group: @user.context_group) + FactoryBot.create(:url, group: @user.context_group) end - describe 'with no urls selected' do - describe 'the bulk actions button ', js: true do - it 'should be disabled' do - expect(page.find('.table-options')[:class]).to( - have_content('disabled') - ) - end - end + it 'has a disabled bulk action button if no urls are selected', retry: 3 do + visit urls_path + expect(page).to have_css('.table-options.disabled') end describe 'with multiple urls selected' do describe 'from different groups' do before do - @new_group = FactoryGirl.create(:group) + @new_group = FactoryBot.create(:group) @new_group.users << @user - @new_group_url = FactoryGirl.create(:url, group: @new_group) + @new_group_url = FactoryBot.create(:url, group: @new_group) sign_in @user visit urls_path + wait_for_urls_page_load find("#url-#{@selected_url.id} > .select-checkbox").click find("#url-#{@new_group_url.id} > .select-checkbox").click find('.table-options').click find('.js-transfer-urls').click - wait_for_ajax + wait_for_modal_to_load + js_make_all_inputs_visible end - it 'should display default group url' do - expect(page).to have_selector(".new_transfer_request input[value='#{@selected_url.keyword}']", visible: false) + it 'displays default group url' do + expect(page).to have_selector(".new_transfer_request input[value='#{@selected_url.keyword}']") end - it 'should display new group url' do - expect(page).to have_selector(".new_transfer_request input[value='#{@new_group_url.keyword}']", visible: false) + it 'displays new group url', retry: 3 do + expect(page).to have_selector(".new_transfer_request input[value='#{@new_group_url.keyword}']") end describe 'submitting a transfer request' do before do - @other_user = FactoryGirl.create(:user) + @other_user = FactoryBot.create(:user) first('input#transfer_request_to_group', visible: false).set @other_user.uid - find('#new_transfer_request input[type="submit"]').click + find('#new_transfer_request input[type="submit"]').click click_button 'Confirm' - wait_for_ajax + wait_for_modal_to_dismiss end - it 'should have all of the urls in the request' do + + it 'has all of the urls in the request' do expect(TransferRequest.last.urls - [@selected_url, @new_group_url]).to be_empty end end @@ -79,12 +79,12 @@ end describe 'with a single url selected' do - before { + before do visit urls_path find("#url-#{@selected_url.id} > .select-checkbox").click wait_for_ajax find('.table-options').click - } + end describe 'clicking the tranfser button' do before do @@ -92,57 +92,63 @@ wait_for_ajax end - it 'should display the modal' do + it 'displays the modal' do expect(page).to have_selector('#index-modal', visible: true) end describe 'filling out the form' do describe 'with valid information' do before do - @other_user = FactoryGirl.create(:user) + @other_user = FactoryBot.create(:user) + js_make_all_inputs_visible first('input#transfer_request_to_group', visible: false).set @other_user.uid end - it 'should create a transfer request' do + it 'creates a transfer request' do expect do find('#new_transfer_request input[type="submit"]').click click_button "Confirm" - wait_for_ajax + wait_for_modal_to_dismiss end.to change(TransferRequest, :count).by(1) end - it 'should display the pending request on your screen' do - find('#new_transfer_request input[type="submit"]').click + it 'displays the pending request on your screen' do + find('#new_transfer_request input[type="submit"]').click click_button "Confirm" - wait_for_ajax + wait_for_modal_to_dismiss expect(page).to have_content 'URLs you gave that are pending approval' end - it 'should display the pending request on their screen' do + it 'displays the pending request on their screen' do find('#new_transfer_request input[type="submit"]').click click_button "Confirm" + wait_for_modal_to_dismiss sign_in(@other_user) visit urls_path + wait_for_urls_page_load expect(page).to have_content 'URLs you are being given' end describe 'user does not exist' do let(:new_uid) { 'notauser123456' } + before do first('input#transfer_request_to_group', visible: false).set new_uid end - it 'should create a new user' do + + it 'creates a new user' do expect do find('#new_transfer_request input[type="submit"]').click click_button "Confirm" - wait_for_ajax + wait_for_modal_to_dismiss end.to change(User, :count).by(1) end - it 'should create a transfer request' do + + it 'creates a transfer request' do expect do find('#new_transfer_request input[type="submit"]').click click_button "Confirm" - wait_for_ajax + wait_for_modal_to_dismiss end.to change(TransferRequest, :count).by(1) end end @@ -150,17 +156,20 @@ describe 'with invalid information' do let(:new_uid) { '' } + describe 'uid is blank' do before do first('input#transfer_request_to_group', visible: false).set new_uid end - it 'should display an error' do + + it 'displays an error' do find('#new_transfer_request input[type="submit"]').click click_button "Confirm" wait_for_ajax expect(page).to have_content 'To group must exist' end - it 'should not create a transfer request' do + + it 'does not create a transfer request' do expect do find('#new_transfer_request input[type="submit"]').click wait_for_ajax @@ -176,12 +185,12 @@ describe 'on the urls details', js: true do before do - @url = FactoryGirl.create(:url, group: @user.context_group) + @url = FactoryBot.create(:url, group: @user.context_group) visit url_path(@url.keyword) end describe 'the trasnfer button' do - it 'should be present' do + it 'is present' do expect(page).to have_selector('.js-transfer-urls') end @@ -191,7 +200,7 @@ wait_for_ajax end - it 'should display the modal' do + it 'displays the modal' do expect(page).to have_selector('#index-modal', visible: true) end end @@ -200,8 +209,8 @@ describe 'intereacting with transfer request', js: true do before do - @other_url = FactoryGirl.create(:url) - @transfer = FactoryGirl.create( + @other_url = FactoryBot.create(:url) + @transfer = FactoryBot.create( :transfer_request, to_group_id: @user.context_group_id, from_group_id: @other_url.group_id, @@ -212,27 +221,31 @@ end describe 'accepting' do - it 'should update the status of the transfer request' do + it 'updates the status of the transfer request' do expect do find('.js-approve-transfer').click wait_for_ajax end.to change(TransferRequest.pending, :count).by(-1) end - it 'should change the status of the transfer to approved' do + + it 'changes the status of the transfer to approved' do + expect(page).to have_css('.js-approve-transfer') expect do find('.js-approve-transfer').click wait_for_ajax @transfer.reload end.to change(@transfer, :status).to('approved') end - it 'should change the owner of the url' do + + it 'changes the owner of the url' do expect do find('.js-approve-transfer').click wait_for_ajax @other_url.reload end.to change(@other_url, :group_id).to(@user.context_group_id) end - it 'should display the url in your list' do + + it 'displays the url in your list' do find('.js-approve-transfer').click wait_for_ajax expect(page).to have_selector("#url-#{@other_url.id}") @@ -240,14 +253,15 @@ end describe 'rejecting' do - it 'should change the status of the the transfer request' do + it 'changes the status of the the transfer request' do expect do find('.js-reject-transfer').click click_button "Confirm" wait_for_ajax end.to change(TransferRequest.pending, :count).by(-1) end - it 'should change the status of the transfer to rejected' do + + it 'changes the status of the transfer to rejected' do expect do find('.js-reject-transfer').click click_button "Confirm" @@ -255,17 +269,19 @@ @transfer.reload end.to change(@transfer, :status).to('rejected') end - it 'should not change the owner of the url' do + + it 'does not change the owner of the url' do expect do find('.js-reject-transfer').click wait_for_ajax @other_url.reload - end.to_not change(@other_url, :group_id) + end.not_to change(@other_url, :group_id) end - it 'should not display the url in your list' do + + it 'does not display the url in your list' do find('.js-reject-transfer').click wait_for_ajax - expect(page).to_not have_selector("#url-#{@other_url.id}") + expect(page).not_to have_selector("#url-#{@other_url.id}") end end end diff --git a/spec/features/urls/url_show_stats_page_spec.rb b/spec/features/urls/url_show_stats_page_spec.rb new file mode 100644 index 00000000..fe18e5b3 --- /dev/null +++ b/spec/features/urls/url_show_stats_page_spec.rb @@ -0,0 +1,117 @@ +# frozen-string-literal: true + +require 'rails_helper' + +describe 'zlink stats page' do + let(:created_at) { Time.zone.now - 1.day } + let(:user) { FactoryBot.create(:user) } + let(:url) do + FactoryBot.create( + :url, + group: user.context_group, + keyword: 'g', + url: 'http//www.google.com', + created_at: created_at + ) + end + + before do + sign_in user + end + + context 'when given a url that does not exist' do + it 'shows not found page' do + visit url_path('doesnotexist') + expect(page).to have_content('Not Found') + end + end + + context 'when given a url that exists', js: true do + before do + # add 10 clicks to yesterday + 10.times do + url.clicks << Click.create( + country_code: 'US', + created_at: Time.zone.now - 1.day + ) + url.total_clicks += 1 + url.save + end + + # add 5 clicks to today + 5.times do + url.clicks << Click.create( + country_code: 'US', + created_at: Time.zone.now + ) + url.total_clicks += 1 + url.save + end + + visit url_path(url.keyword) + end + + it 'displays long url' do + expect(page).to have_content url.url + end + + it 'displays the keyword' do + expect(page).to have_content url.keyword + end + + it 'displays created date' do + expect(page).to have_content created_at.to_s(:created_on_formatted) + end + + it 'displays best day' do + expect(page).to have_content '10 hits' + end + + it 'displays the total clicks' do + expect(page).to have_content '15 hits' + end + + it 'displays the share to twitter button' do + expect(page).to have_selector('.url-share-button-twitter') + end + + it 'displays the download QR code button' do + expect(page).to have_selector('.url-share-button-qr') + end + + describe 'downloading qr code', js: true do + before { find('.url-share-button-qr').click } + + it 'is a png type', retry: 3 do + expect(page.status_code).to eq 200 + expect(page.response_headers['Content-Type']).to eq('image/png') + end + + it 'is not blank' do + expect(page.body).not_to be_blank + end + end + + describe 'collection dropdown' do + let(:new_group) { FactoryBot.create(:group) } + + before do + new_group.users << user + visit url_path(url.keyword) + find('.bootstrap-select .dropdown-toggle').click + accept_confirm do + find('.dropdown-menu.open').find('li', text: new_group.name).click + end + end + + it 'changes the collection' do + expect(page).to have_selector('.bootstrap-select .dropdown-toggle', text: new_group.name) + end + + it 'updates the urls collection in the database' do + url.reload + expect(url.group.id).to eq(new_group.id) + end + end + end +end diff --git a/spec/features/urls/urls_page_collection_assignment_dropdown_spec.rb b/spec/features/urls/urls_page_collection_assignment_dropdown_spec.rb new file mode 100644 index 00000000..3be71c3f --- /dev/null +++ b/spec/features/urls/urls_page_collection_assignment_dropdown_spec.rb @@ -0,0 +1,57 @@ +# frozen-string-literal: true + +require 'rails_helper' + +describe 'collection assignment dropdown', js: true do + let(:user) { FactoryBot.create(:user) } + + before do + @url = FactoryBot.create(:url, group: user.context_group) + @new_group = FactoryBot.create(:group) + @new_group.users << user + sign_in(user) + wait_for_ajax + visit urls_path + wait_for_ajax + find('table .bootstrap-select .dropdown-toggle').click + end + + it 'changes a collection' do + expect(page).to have_content("All") + accept_confirm do + find('.dropdown-menu.open').find('li', text: @new_group.name).click + end + expect(page).to have_selector('table .bootstrap-select .dropdown-toggle', text: @new_group.name) + end + + it 'updates the urls collection in the database' do + expect(page).to have_content("All") + accept_confirm do + find('.dropdown-menu.open').find('li', text: @new_group.name).click + end + @url.reload + expect(@url.group.id).to eq(@new_group.id) + end + + it 'creates a new collection' do + expect(page).to have_content("All") + find('table .dropdown-menu.open .bottom-action-option').click + # modal should display + expect(page).to have_selector('#index-modal') + + # fill in the form + another_group_name = "another group" + another_group_description = "another group description" + find('.modal input#group_name').set another_group_name + find('.modal input#group_description').set another_group_description + find('.modal input[type="submit"]').click + click_button "Confirm" + + # colection picker is updated + expect(page).to have_selector('table .bootstrap-select .dropdown-toggle', text: another_group_name) + + # url in database is updated + @url.reload + expect(@url.group.name).to eq(another_group_name) + end +end diff --git a/spec/features/urls/urls_page_create_new_zlink_spec.rb b/spec/features/urls/urls_page_create_new_zlink_spec.rb new file mode 100644 index 00000000..89cbabaa --- /dev/null +++ b/spec/features/urls/urls_page_create_new_zlink_spec.rb @@ -0,0 +1,131 @@ +# frozen-string-literal: true + +require 'rails_helper' + +describe 'urls index page: creating new zlink', js: true do + let(:user) { FactoryBot.create(:user) } + let(:url) do + 'http://www.gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg.com' + end + let(:keyword) { 'goog' } + + before do + sign_in(user) + end + + it 'shortens a url blurb that is super long' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set keyword + + find('.js-url-submit').click + expect(page).to have_content('gggg...') + end + + it 'shortens a camelCaseKeyword' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set 'aCamelCaseKeyword' + find('.js-url-submit').click + + expect(page).to have_content('aCamelCaseKeyword') + # it does not lower the case + expect(page).not_to have_content('acamelcasekeyword') + end + + it 'does not have active pagination buttons if there is only 1 url' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set keyword + find('.js-url-submit').click + + expect(page).to have_selector('.paginate_button.next.disabled') + expect(page).to have_selector('.paginate_button.previous.disabled') + end + + it 'saves new urls upon clicking create' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set keyword + expect do + find('.js-url-submit').click + end.to change(Url, :count).by(1) + end + + it 'shows url sharing info (url blurb) after creating' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set keyword + find('.js-url-submit').click + + expect(page).to have_selector('.url-blurb') + expect(page.find(".url-blurb-source")).to have_content('gggg...') + expect(page.find(".url-blurb-short-url")).to have_content(keyword) + + # share buttons + expect(page).to have_selector('.url-blurb .url-share-button-twitter') + expect(page).to have_selector('.url-blurb .url-share-button-qr') + end + + it 'downloads a qr code' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set keyword + find('.js-url-submit').click + find('.url-share-button-qr').click + + expect(page.response_headers['Content-Type']).to eq('image/png') + expect(page.body).not_to be_blank + end + + it 'does not save URL if its invalid' do + visit urls_path + find('.js-new-url-url').set ':' + find('.js-new-url-keyword').set keyword + find('.js-url-submit').click + + expect do + find('.js-url-submit').click + wait_for_ajax + end.to change(Url, :count).by(0) + end + + it 'shows an error message if URL is not valid' do + visit urls_path + find('.js-new-url-url').set ':' + find('.js-new-url-keyword').set keyword + find('.js-url-submit').click + + expect(page).to have_content 'Url is not valid.' + end + + it 'treats keyword as optional, creating a new zlink without it' do + visit urls_path + find('.js-new-url-url').set url + find('.js-new-url-keyword').set '' + + expect do + find('.js-url-submit').click + # expect(page).to have_content(url) + end.to change(Url, :count).by(1) + end + + it 'does not create link if keyword is already taken' do + # create another url with the same keyword + @other_url = FactoryBot.create(:url) + + # now try creating a new zlink using the same keyword + visit urls_path + find('.js-new-url-url').set url + find('#url_keyword').set @other_url.keyword + + # No new URL should be created + expect do + find('.js-url-submit').click + wait_for_ajax + end.to change(Url, :count).by(0) + + # Error Message should be displayed + expect(page).to have_content('taken') + end +end diff --git a/spec/features/urls/urls_page_edit_zlink_spec.rb b/spec/features/urls/urls_page_edit_zlink_spec.rb new file mode 100644 index 00000000..fe9916c7 --- /dev/null +++ b/spec/features/urls/urls_page_edit_zlink_spec.rb @@ -0,0 +1,53 @@ +# frozen-string-literal: true + +require 'rails_helper' + +describe 'z index page: when editing existing url', js: true do + let(:user) { FactoryBot.create(:user) } + let(:new_url) { 'http://www.facebook.com' } + let(:new_keyword) { 'face' } + + before do + @url = FactoryBot.create(:url, group: user.context_group) + sign_in(user) + visit urls_path + end + + it 'updates the url in the db' do + find('.dropdown .actions-dropdown-button').click + find('.dropdown-menu .edit-url').click + + find('table #url_url').set new_url + find('table .js-url-submit').click + expect(@url.reload.url).to eq(new_url) + end + + it 'updates the keyword in the db' do + find('.dropdown .actions-dropdown-button').click + find('.dropdown-menu .edit-url').click + find('table #url_keyword').set new_keyword + find('table .js-url-submit').click + expect(@url.reload.keyword).to eq(new_keyword) + end + + it 'deletes the url' do + expect do + find('.dropdown .actions-dropdown-button').click + find('.dropdown-menu .delete-url').click + click_button "Confirm" + end.to change(Url, :count).by(-1) + end + + context 'when user attempts to edit someone elses url' do + let(:another_user) { FactoryBot.create(:user) } + + before do + @another_users_url = FactoryBot.create(:url, group: another_user.context_group) + end + + it 'displays not authorized message' do + visit edit_url_path(@another_users_url) + expect(page).to have_content 'You are not authorized to perform this action.' + end + end +end diff --git a/spec/features/urls/urls_page_list_zlinks_spec.rb b/spec/features/urls/urls_page_list_zlinks_spec.rb new file mode 100644 index 00000000..a4731322 --- /dev/null +++ b/spec/features/urls/urls_page_list_zlinks_spec.rb @@ -0,0 +1,94 @@ +# frozen-string-literal: true + +require 'rails_helper' + +describe 'urls index page: list existing urls', js: true do + let(:user) { FactoryBot.create(:user) } + let(:url) { FactoryBot.create(:url) } + + before do + # set this url to be owned by the user + url.update(group: user.context_group) + + sign_in(user) + visit urls_path + end + + it 'displays the long url' do + expect(page).to have_content url.url + end + + it 'displays short url host' do + expect(page).to have_content page.current_host.sub(%r{^https?://(www.)?}, '') + end + + it 'displays the url\'s keyword' do + expect(page).to have_content url.keyword + end + + it 'displays the url\'s click count' do + expect(page).to have_css('td', text: url.total_clicks) + end + + it 'displays the action dropdown button' do + expect(page).to have_selector('.actions-column .actions-dropdown-button') + end + + it 'displays the default urls display_name' do + expect(page).to have_selector( + "[data-id='url-collection-#{url.id}']", + text: I18n.t('views.urls.index.table.collection_filter.none') + ) + end + + it 'filters on collection', js: true do + # create a new collection + new_group = FactoryBot.create(:group) + + # add current user to it + new_group.users << user + + # add a new url to the collection + new_url = FactoryBot.create(:url, group: new_group) + + # reload page + visit urls_path + + # open the collections dropdown + find('[data-id="collection-filter"]').click + + # choose the new collection from the list + expect(page).to have_content(new_group.name) + find('.dropdown-menu.open li', text: new_group.name).click + + # it shows urls from this collection, but not other collections + expect(page).to have_content new_url.keyword + expect(page).not_to have_content url.keyword + end + + it 'filters on url keyword' do + create_url_for_user(user, { url: 'https://tc.umn.edu', keyword: 'twin-cities' }) + create_url_for_user(user, { url: 'https://mrs.umn.edu', keyword: 'morris' }) + + # type part of the keyword into the searchbox + within '#urls-table_wrapper' do + # based on current factory, last letter of a keyword should be a number + # unique to the zlink + fill_in 'Search', with: 'twin' + expect(page).to have_content('twin-cities') + expect(page).to have_no_content('morris') + end + end + + it 'filters on long url' do + # create urls associated with the User + create_url_for_user(user, { url: 'https://tc.umn.edu', keyword: 'twin-cities' }) + create_url_for_user(user, { url: 'https://mrs.umn.edu', keyword: 'morris' }) + + within '#urls-table_wrapper' do + fill_in 'Search', with: 'tc' + expect(page).to have_content('twin-cities') + expect(page).to have_no_content('morris') + end + end +end diff --git a/spec/features/urls/urls_page_share_zlink_spec.rb b/spec/features/urls/urls_page_share_zlink_spec.rb new file mode 100644 index 00000000..c746261c --- /dev/null +++ b/spec/features/urls/urls_page_share_zlink_spec.rb @@ -0,0 +1,42 @@ +# frozen-string-literal: true + +require 'rails_helper' + +describe 'when sharing existing url', js: true do + let(:user) { FactoryBot.create(:user) } + let(:url) { FactoryBot.create(:url) } + + before do + # set this url to be owned by the user + url.update(group: user.context_group) + + sign_in(user) + visit urls_path + end + + it 'displays the share to twitter button' do + expect(page).to have_selector('.dropdown .actions-dropdown-button') + find('.dropdown .actions-dropdown-button').click + find('.dropdown-menu .share-url').hover + + expect(page).to have_selector('.url-share-button-twitter') + end + + it 'displays the download QR code button' do + expect(page).to have_selector('.dropdown .actions-dropdown-button') + find('.dropdown .actions-dropdown-button').click + find('.dropdown-menu .share-url').hover + + expect(page).to have_selector('.url-share-button-qr') + end + + it 'downloads a qr code', retry: 3 do + expect(page).to have_selector('.dropdown .actions-dropdown-button') + find('.dropdown .actions-dropdown-button').click + find('.dropdown-menu .share-url').hover + + find('.url-share-button-qr').click + expect(page.body).not_to be_blank + expect(page.response_headers['Content-Type']).to eq('image/png') + end +end diff --git a/spec/features/urls_spec.rb b/spec/features/urls_spec.rb deleted file mode 100644 index 44a55a6b..00000000 --- a/spec/features/urls_spec.rb +++ /dev/null @@ -1,429 +0,0 @@ -require 'rails_helper' - -describe 'urls show page', js: true do - let(:keyword) { 'testkeyword' } - let(:url) { 'http://www.google.com' } - let(:created_at) { Time.now - 1.day } - - before do - @user = FactoryGirl.create(:user) - sign_in(@user) - wait_for_ajax - - @url = FactoryGirl.create( - :url, - group: @user.context_group, - keyword: keyword, - url: url, - created_at: created_at - ) - # add 10 clicks to yesterday - 10.times do - @url.clicks << Click.create( - country_code: 'US', - created_at: Time.now - 1.day - ) - @url.total_clicks += 1 - @url.save - end - - # add 5 clicks to today - 5.times do - @url.clicks << Click.create( - country_code: 'US', - created_at: Time.now - ) - @url.total_clicks += 1 - @url.save - end - - visit url_path(@url.keyword) - end - - it 'should display long url' do - expect(page).to have_content url - end - - it 'should display the keyword' do - expect(page).to have_content keyword - end - - it 'should display created date' do - expect(page).to have_content created_at.to_s(:created_on_formatted) - end - - it 'should display best day' do - expect(page).to have_content '10 hits' - end - - it 'should display the total clicks' do - expect(page).to have_content '15 hits' - end - it 'should display the share to twitter button' do - expect(page).to have_selector('.url-share-button-twitter', visible: true) - end - it 'should display the download QR code button' do - expect(page).to have_selector('.url-share-button-qr', visible: true) - end - - describe 'downloading qr code', js: true do - before { find('.url-share-button-qr').click } - - it 'should be a png type' do - expect(page.response_headers['Content-Type']).to eq('image/png') - end - - it 'should not be blank' do - expect(page.body).to_not be_blank - end - end - - describe 'collection dropdown' do - before { - @new_group = FactoryGirl.create(:group) - @new_group.users << @user - sign_in(@user) - wait_for_ajax - visit url_path(@url.keyword) - wait_for_ajax - find('.bootstrap-select .dropdown-toggle').click - find('.dropdown-menu.open').find('li', text: @new_group.name).click - wait_for_ajax - } - - it 'should change the collection' do - expect(page).to have_selector('.bootstrap-select .dropdown-toggle', text: @new_group.name) - end - it 'should update the urls collection in the database' do - @url.reload - expect(@url.group.id).to eq(@new_group.id) - end - end -end -describe 'urls index page', js: true do - before do - @user = FactoryGirl.create(:user) - sign_in(@user) - wait_for_ajax - end - describe 'creating new url ', js: true do - let(:url) { 'http://www.gggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggg.com' } - let(:keyword) { 'goog' } - before do - visit urls_path - wait_for_ajax - find('.js-new-url-url').set url - find('.js-new-url-keyword').set keyword - end - describe 'that is super long' do - it 'should shorten it in the url blurb' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to have_content('gggg...') - end - end - describe 'that has a camel case' do - before {find('.js-new-url-keyword').set 'aCamelCaseKeyword'} - it 'should display the correct case' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to have_content('aCamelCaseKeyword') - end - it 'should not display the lower case' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to_not have_content('acamelcasekeyword') - end - end - describe 'visiting page with one url' do - it ' should not display pagination Next button' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to have_selector('.paginate_button.next.disabled') - end - it ' should not display pagination Previous button' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to have_selector('.paginate_button.previous.disabled') - end - end - end - describe 'creating new url', js: true do - let(:url) { 'http://www.google.com' } - let(:keyword) { 'goog' } - before do - visit urls_path - find('.js-new-url-url').set url - find('.js-new-url-keyword').set keyword - end - describe 'with valid information' do - describe 'when both fields are filled in' do - it 'should save upon clicking Create' do - expect do - find('.js-url-submit').click - wait_for_ajax - end.to change(Url, :count).by(1) - end - end - describe 'after submitting, the url blurb' do - before do - find('.js-url-submit').click - wait_for_ajax - end - - it 'should be visible' do - expect(page).to have_selector('.url-blurb', visible: true) - end - it 'should have the newly created short url' do - expect(page.find(".url-blurb-short-url")).to have_content(keyword) - end - it 'should have the newly created short url' do - expect(page.find(".url-blurb-source")).to have_content(url) - end - it "should display the share to twitter button" do - expect(page).to have_selector('.url-blurb .url-share-button-twitter', visible: true) - end - it "should display the download QR code button" do - expect(page).to have_selector('.url-blurb .url-share-button-qr', visible: true) - end - - describe 'downloading qr code', js: true do - before { find('.url-share-button-qr').click } - - it 'should be a png type' do - expect(page.response_headers['Content-Type']).to eq('image/png') - end - - it 'should not be blank' do - expect(page.body).to_not be_blank - end - end - end - describe 'when the url is not valid' do - before { find('#url_url').set ':' } - it 'should not save upon clicking Create with an error msg' do - expect do - find('.js-url-submit').click - wait_for_ajax - end.to change(Url, :count).by(0) - expect(page).to have_content 'Url is not valid.' - end - end - describe 'when the keyword is blank' do - before { find('#url_keyword').set '' } - it 'should save upon clicking Create' do - expect do - find('.js-url-submit').click - wait_for_ajax - end.to change(Url, :count).by(1) - end - end - end - describe 'with invalid information' do - describe '[keyword]' do - describe 'already taken' do - before do - @other_url = FactoryGirl.create(:url) - find('#url_keyword').set @other_url.keyword - end - it 'should not save upon clicking Create' do - expect do - find('.js-url-submit').click - wait_for_ajax - end.to change(Url, :count).by(0) - end - - it 'should display an error' do - find('.js-url-submit').click - wait_for_ajax - expect(page).to have_content('taken') - end - end - end - end - end - - describe 'with an existing url', js: true do - let(:new_url) { 'http://www.facebook.com' } - let(:new_keyword) { 'face' } - before do - @url = FactoryGirl.create(:url, group: @user.context_group) - visit urls_path - wait_for_ajax - end - - describe 'page content', js: true do - it 'should display the url\'s url' do - expect(page).to have_content @url.url - end - it 'should display short url host' do - expect(page).to have_content page.current_host.sub(/^https?\:\/\/(www.)?/,'') - end - it 'should display the url\'s keyword' do - expect(page).to have_content @url.keyword - end - it 'should display the url\'s click count' do - expect(page).to have_css('td', text: @url.total_clicks) - end - it 'should display the action dropdown button' do - expect(page).to have_selector('.actions-column .actions-dropdown-button') - end - it 'should display the default urls display_name' do - expect(page).to have_selector("[data-id='url-collection-#{@url.id}']", text: I18n.t('views.urls.index.table.collection_filter.none')) - end - - describe 'when filtering on collection', js: true do - before do - new_group = FactoryGirl.create(:group) - new_group.users << @user - sign_in(@user) - @new_url = FactoryGirl.create(:url, group: new_group) - wait_for_ajax - find('[data-id="collection-filter"]').click - find('.dropdown-menu.open li', text: (new_group.name) ).click - end - it 'should display urls from that collection' do - expect(page).to have_content @new_url.keyword - end - it 'should not display urls from another collection' do - expect(page).to_not have_content @url.keyword - end - end - end - - describe 'when sharing existing url', js: true do - before { - find('.dropdown .actions-dropdown-button').click - find('.dropdown-menu .share-url').hover - } - - describe 'when clicking the share button' do - it 'should display the share to twitter button' do - expect(page).to have_selector('.url-share-button-twitter', visible: true) - end - it 'should display the download QR code button' do - expect(page).to have_selector('.url-share-button-qr', visible: true) - end - - describe 'downloading qr code', js: true do - before { find('.url-share-button-qr').click } - - it 'should be a png type' do - expect(page.response_headers['Content-Type']).to eq('image/png') - end - - it 'should not be blank' do - expect(page.body).to_not be_blank - end - end - end - end - describe 'when editing existing url', js: true do - before { - find('.dropdown .actions-dropdown-button').click - find('.dropdown-menu .edit-url').click - } - - describe 'with new valid content' do - it 'should update the url in the db' do - find('table #url_url').set new_url - find('table .js-url-submit').click - wait_for_ajax - expect(@url.reload.url).to eq(new_url) - end - it 'should update the keyword in the db' do - find('table #url_keyword').set new_keyword - find('table .js-url-submit').click - wait_for_ajax - expect(@url.reload.keyword).to eq(new_keyword) - end - end - end - - describe 'when deleting existing url', js: true do - describe 'clicking delete' do - it 'should delete the url' do - expect do - find('.dropdown .actions-dropdown-button').click - find('.dropdown-menu .delete-url').click - click_button "Confirm" - wait_for_ajax - end.to change(Url, :count).by(-1) - end - end - end - - describe 'when attempting to edit someone elses url' do - before do - @new_user = FactoryGirl.create(:user) - @new_url = FactoryGirl.create(:url, group: @new_user.context_group) - visit edit_url_path(@new_url) - end - describe 'page content' do - it 'should display the not authorized message' do - expect(page).to have_content 'You are not authorized to perform this action.' - end - end - end - - describe 'collection dropdown' do - before { - @new_group = FactoryGirl.create(:group) - @new_group.users << @user - sign_in(@user) - wait_for_ajax - visit urls_path - wait_for_ajax - find('table .bootstrap-select .dropdown-toggle').click - } - - describe 'when changing collection' do - before{ - find('.dropdown-menu.open').find('li', text: @new_group.name).click - wait_for_ajax - } - - it 'should change the collection' do - expect(page).to have_selector('table .bootstrap-select .dropdown-toggle', text: @new_group.name) - end - it 'should update the urls collection in the database' do - @url.reload - expect(@url.group.id).to eq(@new_group.id) - end - end - - describe 'when creating a new collection' do - before{ - find('table .dropdown-menu.open .bottom-action-option').click - wait_for_ajax - } - - it 'should display the modal' do - expect(page).to have_selector('#index-modal', visible: true) - end - - describe 'filling out form' do - before{ - @new_group_name = "new group" - @new_group_description = "new group description" - find('.modal input#group_name').set @new_group_name - find('.modal input#group_description').set @new_group_description - find('.modal input[type="submit"]').click - wait_for_ajax - click_button "Confirm" - wait_for_ajax - } - - it 'should update collection picker in table' do - expect(page).to have_selector('table .bootstrap-select .dropdown-toggle', text: @new_group_name) - end - it 'should update url in database' do - @url.reload - expect(@url.group.name).to eq(@new_group_name) - end - - end - end - end - end -end diff --git a/spec/models/announcement_spec.rb b/spec/models/announcement_spec.rb index 6c4a111b..3beeb294 100644 --- a/spec/models/announcement_spec.rb +++ b/spec/models/announcement_spec.rb @@ -1,31 +1,27 @@ # == Schema Information # # Table name: starburst_announcements -=begin -id int(11) No -title text Yes -body text Yes -start_delivering_at datetime Yes -stop_delivering_at datetime Yes -limit_to_users text Yes -created_at datetime Yes -updated_at datetime Yes -category text -=end +# id int(11) No +# title text Yes +# body text Yes +# start_delivering_at datetime Yes +# stop_delivering_at datetime Yes +# limit_to_users text Yes +# created_at datetime Yes +# updated_at datetime Yes +# category text require 'rails_helper' RSpec.describe Admin::Announcement, type: :model do - before do - @announcement = FactoryGirl.build(:announcement) - end - subject { @announcement } - it { should be_valid } - it { should respond_to 'title' } - it { should respond_to 'body' } - it { should respond_to 'stop_delivering_at'} - it { should respond_to 'start_delivering_at'} - + before do + @announcement = FactoryBot.build(:announcement) + end + it { is_expected.to be_valid } + it { is_expected.to respond_to 'title' } + it { is_expected.to respond_to 'body' } + it { is_expected.to respond_to 'stop_delivering_at' } + it { is_expected.to respond_to 'start_delivering_at' } end diff --git a/spec/models/click_spec.rb b/spec/models/click_spec.rb new file mode 100644 index 00000000..32b91c2f --- /dev/null +++ b/spec/models/click_spec.rb @@ -0,0 +1,90 @@ +# frozen_string_literal: true + +require 'rails_helper' + +def repeatedly_click(url: nil, days_ago: 0, times: 10) + url ||= FactoryBot.create(:url) + times.times do + Click.create(url_id: url.id, country_code: 'US', created_at: days_ago.days.ago) + end +end + +RSpec.describe Click, type: :model do + subject(:click) do + url = FactoryBot.create(:url) + described_class.new( + url_id: url.id, + country_code: 'US' + ) + end + + it { is_expected.to be_valid } + it { is_expected.to be_a(described_class) } + it { is_expected.to belong_to(:url) } + + it 'is invalid without a url' do + click.url_id = nil + expect(click).not_to be_valid + end + + describe('click summaries') do + let(:url1) { FactoryBot.create(:url) } + let(:url2) { FactoryBot.create(:url) } + + before do + repeatedly_click(url: url1, times: 1, days_ago: 0) + repeatedly_click(url: url1, times: 2, days_ago: 1) + repeatedly_click(url: url1, times: 3, days_ago: 2) + repeatedly_click(url: url2, times: 100, days_ago: 0) + end + + describe('.group_by_time_ago') do + year_month_day_strf = '%Y-%m-%d' + + # this feels like word salad + it 'counts url clicks over a given duration, returning a hash keyed by a given time format string' do + expect(url1.clicks.group_by_time_ago(3.days, year_month_day_strf)) + .to eq({ + 2.days.ago.strftime(year_month_day_strf) => 3, + 1.day.ago.strftime(year_month_day_strf) => 2, + Time.zone.now.strftime(year_month_day_strf) => 1 + }) + + expect(url2.clicks.group_by_time_ago(3.days, year_month_day_strf)) + .to eq({ + Time.zone.now.strftime(year_month_day_strf) => 100 + }) + + # total clicks + expect(described_class.group_by_time_ago(3.days, year_month_day_strf)) + .to eq({ + 2.days.ago.strftime(year_month_day_strf) => 3, + 1.day.ago.strftime(year_month_day_strf) => 2, + Time.zone.now.strftime(year_month_day_strf) => 101 + }) + end + + it 'is sorted by oldest to most current dates' do + # add new clicks, but pretend they're older + repeatedly_click(url: url1, times: 1, days_ago: 7) + clicks_by_day_hash = url1.clicks.group_by_time_ago(10.days, year_month_day_strf) + expect(clicks_by_day_hash.to_a) + .to eq([ + [7.days.ago.strftime(year_month_day_strf), 1], + [2.days.ago.strftime(year_month_day_strf), 3], + [1.day.ago.strftime(year_month_day_strf), 2], + [Time.zone.now.strftime(year_month_day_strf), 1] + ]) + end + end + + describe('.max_by_day') do + it 'shows the best day and number of clicks' do + # all clicks + expect(described_class.max_by_day).to eq([Date.current, 101]) + # clicks specific to a url + expect(url1.clicks.max_by_day).to eq([Date.current - 2.days, 3]) + end + end + end +end diff --git a/spec/models/frequently_asked_question_spec.rb b/spec/models/frequently_asked_question_spec.rb index a3f37073..a5d586a4 100644 --- a/spec/models/frequently_asked_question_spec.rb +++ b/spec/models/frequently_asked_question_spec.rb @@ -1,17 +1,16 @@ require 'rails_helper' RSpec.describe FrequentlyAskedQuestion, type: :model do - before do - @frequently_asked_question = FactoryGirl.build(:frequently_asked_question) - end - subject { @frequently_asked_question } - it { should be_valid } - it { should respond_to 'header' } - it { should respond_to 'question' } - it { should respond_to 'answer' } - it { should respond_to 'created_at' } - it { should respond_to 'updated_at' } + before do + @frequently_asked_question = FactoryBot.build(:frequently_asked_question) + end + it { is_expected.to be_valid } + it { is_expected.to respond_to 'header' } + it { is_expected.to respond_to 'question' } + it { is_expected.to respond_to 'answer' } + it { is_expected.to respond_to 'created_at' } + it { is_expected.to respond_to 'updated_at' } end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index b68302c0..9c2f00c5 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -11,21 +11,21 @@ require 'rails_helper' RSpec.describe Group, type: :model do + subject { @group } + before do - @group = FactoryGirl.build(:group) + @group = FactoryBot.build(:group) end - subject { @group } - - it { should be_valid } - it { should respond_to 'name' } - it { should respond_to 'description' } - it { should respond_to 'created_at' } - it { should respond_to 'updated_at' } + it { is_expected.to be_valid } + it { is_expected.to respond_to 'name' } + it { is_expected.to respond_to 'description' } + it { is_expected.to respond_to 'created_at' } + it { is_expected.to respond_to 'updated_at' } describe 'Versioning' do it 's should be enabled' do - is_expected.to be_versioned + expect(subject).to be_versioned end end @@ -33,8 +33,9 @@ describe '[name]' do describe 'doesn\'t exist' do before { @group.name = '' } - it 'should not be valid' do - expect(@group).to_not be_valid + + it 'is not valid' do + expect(@group).not_to be_valid end end end @@ -42,11 +43,13 @@ describe 'calling add_user' do before do - @user = FactoryGirl.create(:user) - @group = FactoryGirl.create(:group) + @user = FactoryBot.create(:user) + @group = FactoryBot.create(:group) end + describe 'should add a user' do - before {@group.add_user @user} + before { @group.add_user @user } + it ' and include user in group.users' do expect(@group.users).to include(@user) end @@ -55,31 +58,35 @@ describe 'calling user?' do before do - @user = FactoryGirl.create(:user) - @user_not = FactoryGirl.create(:user) - @group = FactoryGirl.create(:group) + @user = FactoryBot.create(:user) + @user_not = FactoryBot.create(:user) + @group = FactoryBot.create(:group) @group.add_user @user end + describe 'should have a user' do it ' and return true when asked if user?' do - expect(@group.user? @user).to be true + expect(@group.user?(@user)).to be true end end + describe 'should not have a user' do it ' and return true when asked if user?' do - expect(@group.user? @user_not).to be false + expect(@group.user?(@user_not)).to be false end end end describe 'calling remove_user' do before do - @user = FactoryGirl.create(:user) - @group = FactoryGirl.create(:group) + @user = FactoryBot.create(:user) + @group = FactoryBot.create(:group) @group.add_user @user end + describe 'should have and remove user:' do - before {@group.remove_user @user} + before { @group.remove_user @user } + it 'and then remove it' do expect(@group.users).not_to include(@user) end @@ -88,14 +95,14 @@ describe 'calling default?' do before do - @default_group = FactoryGirl.create(:user).default_group + @default_group = FactoryBot.create(:user).default_group end - it 'should be false for non-default groups' do + it 'is false for non-default groups' do expect(@group.default?).to eq(false) end - it 'should be true for default groups' do + it 'is true for default groups' do expect(@default_group.default?).to eq(true) end end diff --git a/spec/models/transfer_request_spec.rb b/spec/models/transfer_request_spec.rb index 59d90e1d..43b4a52c 100644 --- a/spec/models/transfer_request_spec.rb +++ b/spec/models/transfer_request_spec.rb @@ -1,96 +1,100 @@ require 'rails_helper' RSpec.describe TransferRequest, type: :model do + subject { @transfer_request } + before do - @transfer_request = FactoryGirl.build(:transfer_request) + @transfer_request = FactoryBot.build(:transfer_request) end - subject { @transfer_request } - - it { should be_valid } - it { should respond_to 'to_group' } - it { should respond_to 'to_group_id' } - it { should respond_to 'from_group' } - it { should respond_to 'from_group_id' } + it { is_expected.to be_valid } + it { is_expected.to respond_to 'to_group' } + it { is_expected.to respond_to 'to_group_id' } + it { is_expected.to respond_to 'from_group' } + it { is_expected.to respond_to 'from_group_id' } - it { should respond_to 'created_at' } - it { should respond_to 'updated_at' } + it { is_expected.to respond_to 'created_at' } + it { is_expected.to respond_to 'updated_at' } describe 'Versioning' do - it 'should be enabled' do - is_expected.to be_versioned + it 'is enabled' do + expect(subject).to be_versioned end end describe 'for admin in the from group of the request' do - before do - @admin_user = FactoryGirl.create(:admin) - @transfer_url = FactoryGirl.create(:url) - @transfer_url.group_id = @admin_user.context_group_id - @transfer_request.urls << @transfer_url - @transfer_request.save - end - it 'status should be pending' do - expect(@transfer_request.status.eql? 'pending').to be true - end + before do + @admin_user = FactoryBot.create(:admin) + @transfer_url = FactoryBot.create(:url) + @transfer_url.group_id = @admin_user.context_group_id + @transfer_request.urls << @transfer_url + @transfer_request.save + end + + it 'status should be pending' do + expect(@transfer_request.status.eql?('pending')).to be true + end end describe 'for an admin not in either of the groups of a url' do before do - @user1 = FactoryGirl.create(:user) - @user2 = FactoryGirl.create(:user) - @admin_user = FactoryGirl.create(:admin) + @user1 = FactoryBot.create(:user) + @user2 = FactoryBot.create(:user) + @admin_user = FactoryBot.create(:admin) @transfer_request.from_group_id = - @user1.context_group_id + @user1.context_group_id @transfer_request.to_group_id = - @user2.context_group_id + @user2.context_group_id @transfer_request.from_user = - @admin_user - @transfer_request.to_user= - @user2 + @admin_user + @transfer_request.to_user = + @user2 @transfer_request.save end + it 'status should be approved' do - expect(@transfer_request.status.eql? 'approved').to be true + expect(@transfer_request.status.eql?('approved')).to be true end end - describe 'invalid TransferRequest' do describe '[to_group]' do describe "doesn't exist" do before { @transfer_request.to_group = nil } - it 'should not be valid' do - expect(@transfer_request).to_not be_valid + it 'is not valid' do + expect(@transfer_request).not_to be_valid end end end + describe '[from_group]' do describe "doesn't exist" do before { @transfer_request.from_group = nil } - it 'should not be valid' do - expect(@transfer_request).to_not be_valid + it 'is not valid' do + expect(@transfer_request).not_to be_valid end end + describe "doesn't own urls" do describe 'and is not admin' do - before { @transfer_request.urls = [FactoryGirl.create(:url)] } + before { @transfer_request.urls = [FactoryBot.create(:url)] } - it 'should not be valid' do - expect(@transfer_request).to_not be_valid + it 'is not valid' do + expect(@transfer_request).not_to be_valid end end + describe 'and is an admin' do before do @transfer_request.from_group_id = - FactoryGirl.create(:admin).context_group_id + FactoryBot.create(:admin).context_group_id end - it 'should be valid' do + it 'is valid' do expect(@transfer_request).to be_valid end end diff --git a/spec/models/url_spec.rb b/spec/models/url_spec.rb index 1f8e50c0..d233ed15 100644 --- a/spec/models/url_spec.rb +++ b/spec/models/url_spec.rb @@ -15,25 +15,25 @@ require 'rails_helper' RSpec.describe Url, type: :model do + subject { @url } + before do - @url = FactoryGirl.build(:url) + @url = FactoryBot.build(:url) end - subject { @url } - - it { should be_valid } - it { should respond_to 'total_clicks' } - it { should respond_to 'group' } - it { should respond_to 'group_id' } - it { should respond_to 'keyword' } - it { should respond_to 'url' } - it { should respond_to 'modified_by' } - it { should respond_to 'created_at' } - it { should respond_to 'updated_at' } + it { is_expected.to be_valid } + it { is_expected.to respond_to 'total_clicks' } + it { is_expected.to respond_to 'group' } + it { is_expected.to respond_to 'group_id' } + it { is_expected.to respond_to 'keyword' } + it { is_expected.to respond_to 'url' } + it { is_expected.to respond_to 'modified_by' } + it { is_expected.to respond_to 'created_at' } + it { is_expected.to respond_to 'updated_at' } describe 'Versioning' do it 's should be enabled' do - is_expected.to be_versioned + expect(subject).to be_versioned end end @@ -41,11 +41,12 @@ describe '[keyword]' do describe 'already exists' do before do - other_url = FactoryGirl.create(:url) + other_url = FactoryBot.create(:url) @url.keyword = other_url.keyword end - it 'should not be valid' do - expect(@url).to_not be_valid + + it 'is not valid' do + expect(@url).not_to be_valid end end end @@ -57,359 +58,354 @@ @url.keyword = '-' expect(@url).to be_valid end + it ' underscores should be valid' do @url.keyword = '_' expect(@url).to be_valid end + it ' number should be valid' do @url.keyword = '1234567890' expect(@url).to be_valid end + it ' lowercase letters be valid' do @url.keyword = 'abcdefghijklmnopqrstuvwxyz' expect(@url).to be_valid end + it ' uppercase letters should be valid' do @url.keyword = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' expect(@url).to be_valid end + it ' anything but a-zA-Z0-9\-_ chars should not be valid' do %w(! @ # $ $ % ^ & * ( ) ,).each do |x| @url.keyword = x - expect(@url).to_not be_valid + expect(@url).not_to be_valid end end end + describe 'various urls' do - it 'should be valid' do + it 'is valid' do @url.url = 'http://fun.com' expect(@url).to be_valid end - it 'should not be valid' do + it 'is not valid' do @url.url = 'Http://fun.net' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'https://fun.com' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'http://fun.com' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'Https://fun.com' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'fun.com' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'fun' expect(@url).to be_valid end - it 'should not be valid' do + it 'is not valid' do @url.url = ':' - expect(@url).to_not be_valid + expect(@url).not_to be_valid end - it 'should not be valid' do + it 'is not valid' do @url.url = '\\' - expect(@url).to_not be_valid + expect(@url).not_to be_valid end - it 'should not be valid' do + it 'is not valid' do @url.url = '%' - expect(@url).to_not be_valid - end - -=begin -Berners-Lee, et al. Standards Track [Page 36] - -RFC 3986 URI Generic Syntax January 2005 - -5.4.1. Normal Examples - - "g:h" = "g:h" - "g" = "http://a/b/c/g" - "./g" = "http://a/b/c/g" - "g/" = "http://a/b/c/g/" - "/g" = "http://a/g" - "//g" = "http://g" - "?y" = "http://a/b/c/d;p?y" - "g?y" = "http://a/b/c/g?y" - "#s" = "http://a/b/c/d;p?q#s" - "g#s" = "http://a/b/c/g#s" - "g?y#s" = "http://a/b/c/g?y#s" - ";x" = "http://a/b/c/;x" - "g;x" = "http://a/b/c/g;x" - "g;x?y#s" = "http://a/b/c/g;x?y#s" - ";x" = "http://a/b/c/d;p?q" - "." = "http://a/b/c/" - "./" = "http://a/b/c/" - ".." = "http://a/b/" - "../" = "http://a/b/" - "../g" = "http://a/b/g" - "../.." = "http://a/" - "../../" = "http://a/" - "../../g" = "http://a/g" -=end - - it 'should be valid' do + expect(@url).not_to be_valid + end + + # Berners-Lee, et al. Standards Track [Page 36] + # + # RFC 3986 URI Generic Syntax January 2005 + # + # 5.4.1. Normal Examples + # + # "g:h" = "g:h" + # "g" = "http://a/b/c/g" + # "./g" = "http://a/b/c/g" + # "g/" = "http://a/b/c/g/" + # "/g" = "http://a/g" + # "//g" = "http://g" + # "?y" = "http://a/b/c/d;p?y" + # "g?y" = "http://a/b/c/g?y" + # "#s" = "http://a/b/c/d;p?q#s" + # "g#s" = "http://a/b/c/g#s" + # "g?y#s" = "http://a/b/c/g?y#s" + # ";x" = "http://a/b/c/;x" + # "g;x" = "http://a/b/c/g;x" + # "g;x?y#s" = "http://a/b/c/g;x?y#s" + # ";x" = "http://a/b/c/d;p?q" + # "." = "http://a/b/c/" + # "./" = "http://a/b/c/" + # ".." = "http://a/b/" + # "../" = "http://a/b/" + # "../g" = "http://a/b/g" + # "../.." = "http://a/" + # "../../" = "http://a/" + # "../../g" = "http://a/g" + + it 'is valid' do @url.url = 'g:h' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = './g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g/' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '/g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '//g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '?y' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g?y' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '#s' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g#s' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g?y#s' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = ';x' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '.' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '/' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '..' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '../' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '../g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '../..' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '../../' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '../../g' expect(@url).to be_valid end -=begin -Berners-Lee, et al. Standards Track [Page 36] - -RFC 3986 URI Generic Syntax January 2005 - - -5.4.2. Abnormal Examples - - Although the following abnormal examples are unlikely to occur in - normal practice, all URI parsers should be capable of resolving them - consistently. Each example uses the same base as that above. - - Parsers must be careful in handling cases where there are more ".." - segments in a relative-path reference than there are hierarchical - levels in the base URI's path. Note that the ".." syntax cannot be - used to change the authority component of a URI. - - "../../../g" = "http://a/g" - "../../../../g" = "http://a/g" -=end - - it 'should be valid' do + # Berners-Lee, et al. Standards Track [Page 36] + # + # RFC 3986 URI Generic Syntax January 2005 + # + # 5.4.2. Abnormal Examples + # + # Although the following abnormal examples are unlikely to occur in + # normal practice, all URI parsers should be capable of resolving them + # consistently. Each example uses the same base as that above. + # + # Parsers must be careful in handling cases where there are more ".." + # segments in a relative-path reference than there are hierarchical + # levels in the base URI's path. Note that the ".." syntax cannot be + # used to change the authority component of a URI. + # + # "../../../g" = "http://a/g" + # "../../../../g" = "http://a/g" + + it 'is valid' do @url.url = '../../../g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '../../../../g' expect(@url).to be_valid end -=begin - Similarly, parsers must remove the dot-segments "." and ".." when - they are complete components of a path, but not when they are only - part of a segment. - - "/./g" = "http://a/g" - "/../g" = "http://a/g" - "g." = "http://a/b/c/g." - ".g" = "http://a/b/c/.g" - "g.." = "http://a/b/c/g.." - "..g" = "http://a/b/c/..g" -=end + # Similarly, parsers must remove the dot-segments "." and ".." when + # they are complete components of a path, but not when they are only + # part of a segment. + # + # "/./g" = "http://a/g" + # "/../g" = "http://a/g" + # "g." = "http://a/b/c/g." + # ".g" = "http://a/b/c/.g" + # "g.." = "http://a/b/c/g.." + # "..g" = "http://a/b/c/..g" - it 'should be valid' do + it 'is valid' do @url.url = '/./g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '/../g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g.' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '.g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g..' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = '..g' expect(@url).to be_valid end -=begin - Less likely are cases where the relative reference uses unnecessary - or nonsensical forms of the "." and ".." complete path segments. - - "./../g" = "http://a/b/g" - "./g/." = "http://a/b/c/g/" - "g/./h" = "http://a/b/c/g/h" - "g/../h" = "http://a/b/c/h" - "g;x=1/./y" = "http://a/b/c/g;x=1/y" - "g;x=1/../y" = "http://a/b/c/y" -=end - it 'should be valid' do + # Less likely are cases where the relative reference uses unnecessary + # or nonsensical forms of the "." and ".." complete path segments. + # + # "./../g" = "http://a/b/g" + # "./g/." = "http://a/b/c/g/" + # "g/./h" = "http://a/b/c/g/h" + # "g/../h" = "http://a/b/c/h" + # "g;x=1/./y" = "http://a/b/c/g;x=1/y" + # "g;x=1/../y" = "http://a/b/c/y" + it 'is valid' do @url.url = './../g' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = './g/' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g/./h' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g/../h' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g;x=1/./y' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g;x=1/../y' expect(@url).to be_valid end -=begin - Some applications fail to separate the reference's query and/or - fragment components from the path component before merging it with - the base path and removing dot-segments. This error is rarely - noticed, as typical usage of a fragment never includes the hierarchy - ("/") character and the query component is not normally used within - relative references. - - "g?y/./x" = "http://a/b/c/g?y/./x" - "g?y/../x" = "http://a/b/c/g?y/../x" - "g#s/./x" = "http://a/b/c/g#s/./x" - "g#s/../x" = "http://a/b/c/g#s/../x" -=end - it 'should be valid' do + + # Some applications fail to separate the reference's query and/or + # fragment components from the path component before merging it with + # the base path and removing dot-segments. This error is rarely + # noticed, as typical usage of a fragment never includes the hierarchy + # ("/") character and the query component is not normally used within + # relative references. + # + # "g?y/./x" = "http://a/b/c/g?y/./x" + # "g?y/../x" = "http://a/b/c/g?y/../x" + # "g#s/./x" = "http://a/b/c/g#s/./x" + # "g#s/../x" = "http://a/b/c/g#s/../x" + it 'is valid' do @url.url = 'g?y/./x' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g?y/../x' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g#s/./x' expect(@url).to be_valid end - it 'should be valid' do + it 'is valid' do @url.url = 'g#s/../x' expect(@url).to be_valid end - end end end diff --git a/spec/policies/admin_membership_policy_spec.rb b/spec/policies/admin_membership_policy_spec.rb index 5ac1c820..769ab483 100644 --- a/spec/policies/admin_membership_policy_spec.rb +++ b/spec/policies/admin_membership_policy_spec.rb @@ -5,17 +5,17 @@ subject { described_class } before do - @admin_user = FactoryGirl.create(:user, admin: true, uid: 'wozniak') - @bad_user = FactoryGirl.create(:user, admin: false, uid: 'andersen') + @admin_user = FactoryBot.create(:user, admin: true, uid: 'wozniak') + @bad_user = FactoryBot.create(:user, admin: false, uid: 'andersen') end permissions :destroy?, :create?, :index? do it 'allows access if user is an admin' do expect(subject).to permit(@admin_user) end + it 'denies access if user is not admin' do expect(subject).not_to permit(@bad_user) end end - -end \ No newline at end of file +end diff --git a/spec/policies/audit_policy_spec.rb b/spec/policies/audit_policy_spec.rb index 91c3ccfd..47d50517 100644 --- a/spec/policies/audit_policy_spec.rb +++ b/spec/policies/audit_policy_spec.rb @@ -5,17 +5,17 @@ subject { described_class } before do - @admin_user = FactoryGirl.create(:user, admin: true, uid: 'wozniak') - @bad_user = FactoryGirl.create(:user, admin: false, uid: 'andersen') + @admin_user = FactoryBot.create(:user, admin: true, uid: 'wozniak') + @bad_user = FactoryBot.create(:user, admin: false, uid: 'andersen') end permissions :index? do it 'allows access if user is an admin' do expect(subject).to permit(@admin_user) end + it 'denies access if user is not admin' do expect(subject).not_to permit(@bad_user) end end - -end \ No newline at end of file +end diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index 1675134d..624792e3 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -1,30 +1,28 @@ require "pundit/rspec" require 'rails_helper' - describe GroupPolicy do subject { described_class } before do - @group = FactoryGirl.create(:group) - @good_user = FactoryGirl.create(:user) + @group = FactoryBot.create(:group) + @good_user = FactoryBot.create(:user) @group.add_user(@good_user, false) - @bad_user = FactoryGirl.create(:user) - @admin_user = FactoryGirl.create(:user, admin: true, uid: 'wozniak') + @bad_user = FactoryBot.create(:user) + @admin_user = FactoryBot.create(:user, admin: true, uid: 'wozniak') end permissions :update?, :destroy?, :show?, :index? do it 'allows access if user is an admin' do expect(subject).to permit(@admin_user, @group) end + it 'denies access if user is not part of the group' do expect(subject).not_to permit(@bad_user, @group) end + it 'allows access if user is part of the group' do expect(subject).to permit(@good_user, @group) end end - end - - diff --git a/spec/policies/transfer_request_policy_spec.rb b/spec/policies/transfer_request_policy_spec.rb index fa35e616..201c1620 100644 --- a/spec/policies/transfer_request_policy_spec.rb +++ b/spec/policies/transfer_request_policy_spec.rb @@ -1,29 +1,30 @@ require "pundit/rspec" require 'rails_helper' - describe TransferRequestPolicy do subject { described_class } before do - @admin_user = FactoryGirl.create(:user, admin: true) - @bad_user = FactoryGirl.create(:user, admin: false) - @good_user = FactoryGirl.create(:user) - @group = FactoryGirl.create(:group) + @admin_user = FactoryBot.create(:user, admin: true) + @bad_user = FactoryBot.create(:user, admin: false) + @good_user = FactoryBot.create(:user) + @group = FactoryBot.create(:group) @group.add_user(@good_user, false) - @transfer_request = FactoryGirl.create(:transfer_request) + @transfer_request = FactoryBot.create(:transfer_request) @transfer_request.update(from_group: @group) end - permissions :destroy?, :update?, :show?, :confirm? do + permissions :destroy?, :update?, :show?, :confirm? do it 'allows access if user is an admin' do expect(subject).to permit(@admin_user, @transfer_request) end + it 'allows access if user is in the from group of the transfer' do expect(subject).to permit(@good_user, @transfer_request) end + it 'denies access if user is not in group and not admin' do expect(subject).not_to permit(@bad_user, @transfer_request) end end -end \ No newline at end of file +end diff --git a/spec/policies/url_policy_spec.rb b/spec/policies/url_policy_spec.rb index a3118f89..e2c7c8ff 100644 --- a/spec/policies/url_policy_spec.rb +++ b/spec/policies/url_policy_spec.rb @@ -1,20 +1,19 @@ require "pundit/rspec" require 'rails_helper' - describe UrlPolicy do subject { described_class } before do - @good_user = FactoryGirl.create(:user) - @bad_user = FactoryGirl.create(:user) - @admin_user = FactoryGirl.create(:user, admin: true, uid: 'wozniak') - @url = FactoryGirl.create( - :url, - group: @good_user.context_group, - keyword: 'keyword', - url: 'http://google.com', - created_at: 'created_at' + @good_user = FactoryBot.create(:user) + @bad_user = FactoryBot.create(:user) + @admin_user = FactoryBot.create(:user, admin: true, uid: 'wozniak') + @url = FactoryBot.create( + :url, + group: @good_user.context_group, + keyword: 'keyword', + url: 'http://google.com', + created_at: 'created_at' ) end @@ -22,9 +21,11 @@ it 'allows access if user is part of the Urls group' do expect(subject).to permit(@good_user, @url) end + it 'allows access if user is an admin' do expect(subject).to permit(@admin_user, @url) end + it 'denies access if user is not part of the urls group' do expect(subject).not_to permit(@bad_user, @url) end @@ -34,9 +35,9 @@ it 'allows access if user is an admin' do expect(subject).to permit(@admin_user, @url) end + it 'denies access if user is not an admin' do expect(subject).not_to permit(@bad_user, @url) end end - end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 5eb0cbe0..f6511816 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,20 +1,24 @@ # This file is copied to spec/ when you run 'rails generate rspec:install' ENV['RAILS_ENV'] ||= 'test' require 'spec_helper' -require File.expand_path('../../config/environment', __FILE__) +require File.expand_path('../config/environment', __dir__) require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! require 'support/wait_for_ajax' -require 'support/factory_girl' +require 'support/factory_bot' require 'support/database_cleaner' require 'support/utilities' require 'capybara/rspec' -require 'capybara/poltergeist' - +require 'capybara-screenshot/rspec' require 'paper_trail/frameworks/rspec' +require 'capybara/apparition' + +Capybara.javascript_driver = :apparition -Capybara.javascript_driver = :poltergeist +# For better looking HTML screenshots +# See: https://github.com/mattheworiordan/capybara-screenshot +Capybara.asset_host = 'http://localhost:3000' # Requires supporting ruby files with custom matchers and macros, etc, in # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are @@ -29,7 +33,7 @@ # directory. Alternatively, in the individual `*_spec.rb` files, manually # require only the support files necessary. # -Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} +Dir[Rails.root.join("spec/support/**/*.rb")].sort.each { |f| require f } # Checks for pending migrations before tests are run. # If you are not using ActiveRecord, you can remove this line. @@ -58,4 +62,11 @@ # The different available types are documented in the features, such as in # https://relishapp.com/rspec/rspec-rails/docs config.infer_spec_type_from_file_location! -end \ No newline at end of file +end + +Shoulda::Matchers.configure do |config| + config.integrate do |with| + with.test_framework :rspec + with.library :rails + end +end diff --git a/spec/services/user_lookup_service_spec.rb b/spec/services/user_lookup_service_spec.rb deleted file mode 100644 index c9119705..00000000 --- a/spec/services/user_lookup_service_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -# spec/services/user_lookup_service_test.rb - -require 'rails_helper' - -RSpec.describe UserLookupService, type: :service do - describe 'it can lookup by umndid' do - let(:umndid) { "2qggnq4v3" } - let(:fakeumndid) { "as;ldfjoqujfas;lkdfjalsk;dfj" } - - it 'should find users' do - users = UserLookupService.new( - query: umndid, - query_type: 'umndid' - ).search - expect(users).to be_present - end - - it 'should not find fake users' do - users = UserLookupService.new( - query: fakeumndid, - query_type: 'umndid' - ).search - - expect(users).to be_empty - end - end - - describe 'it can lookup by internet_id' do - let(:internetid) { 'andersen' } - let(:fake_internetid) { 'alsdfjal;iasdl;ifjasdl;ifjadsli;fjndersen@umn.edu' } - - it 'should find one user' do - users = UserLookupService.new( - query: internetid, - query_type: 'all' - ).search - expect(users).to be_present - end - it 'should not find a fake user' do - users = UserLookupService.new( - query: fake_internetid, - query_type: 'all' - ).search - expect(users).to be_empty - end - end -end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index b0fdba37..66f0bb55 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -38,48 +38,46 @@ mocks.verify_partial_doubles = true end -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # These two settings work together to allow you to limit a spec run - # to individual examples or groups you care about by tagging them with - # `:focus` metadata. When nothing is tagged with `:focus`, all examples - # get run. - config.filter_run :focus - config.run_all_when_everything_filtered = true - - # Limits the available syntax to the non-monkey patched syntax that is recommended. - # For more details, see: - # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax - # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = 'doc' - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end -end \ No newline at end of file + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # These two settings work together to allow you to limit a spec run + # # to individual examples or groups you care about by tagging them with + # # `:focus` metadata. When nothing is tagged with `:focus`, all examples + # # get run. + # config.filter_run :focus + # config.run_all_when_everything_filtered = true + # + # # Limits the available syntax to the non-monkey patched syntax that is recommended. + # # For more details, see: + # # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax + # # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching + # config.disable_monkey_patching! + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = 'doc' + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed +end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb index 008f5e77..018d8c25 100644 --- a/spec/support/api_helper.rb +++ b/spec/support/api_helper.rb @@ -7,5 +7,5 @@ def app end RSpec.configure do |config| - config.include ApiHelper, :type=>:api #apply to all spec for apis folder -end \ No newline at end of file + config.include ApiHelper, type: :api # apply to all spec for apis folder +end diff --git a/spec/support/benchmark_helper.rb b/spec/support/benchmark_helper.rb new file mode 100644 index 00000000..6aaf49dc --- /dev/null +++ b/spec/support/benchmark_helper.rb @@ -0,0 +1,14 @@ +require 'benchmark' + +module BenchmarkHelper + def log(msg) + result = nil + time = Benchmark.measure { result = yield } + puts "⏱️ [BENCHMARK] #{format('%8.6s', time.real)}s | #{msg}" + result + end +end + +RSpec.configure do |config| + config.include BenchmarkHelper, type: :feature +end diff --git a/spec/support/database_cleaner.rb b/spec/support/database_cleaner.rb index b5af0d75..1a858429 100644 --- a/spec/support/database_cleaner.rb +++ b/spec/support/database_cleaner.rb @@ -1,5 +1,4 @@ RSpec.configure do |config| - config.use_transactional_fixtures = false config.before(:suite) do @@ -15,10 +14,11 @@ uncommitted transaction data setup over the spec's database connection. MSG end + DatabaseCleaner.clean_with(:truncation) end - config.before(:each) do + config.before do DatabaseCleaner.strategy = :transaction end @@ -27,7 +27,7 @@ # with the specs, so continue to use transaction strategy for speed. driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test - if !driver_shares_db_connection_with_specs + unless driver_shares_db_connection_with_specs # Driver is probably for an external browser with an app # under test that does *not* share a database connection with the # specs, so use truncation strategy. @@ -35,12 +35,11 @@ end end - config.before(:each) do + config.before do DatabaseCleaner.start end - config.append_after(:each) do + config.append_after do DatabaseCleaner.clean end - -end \ No newline at end of file +end diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb new file mode 100644 index 00000000..8fed9e61 --- /dev/null +++ b/spec/support/factory_bot.rb @@ -0,0 +1,4 @@ +# RSpec +RSpec.configure do |config| + config.include FactoryBot::Syntax::Methods +end diff --git a/spec/support/factory_girl.rb b/spec/support/factory_girl.rb deleted file mode 100644 index a73aa8e8..00000000 --- a/spec/support/factory_girl.rb +++ /dev/null @@ -1,5 +0,0 @@ -# RSpec -# spec/support/factory_girl.rb -RSpec.configure do |config| - config.include FactoryGirl::Syntax::Methods -end diff --git a/spec/support/js_test_helpers.rb b/spec/support/js_test_helpers.rb new file mode 100644 index 00000000..8c9d4f95 --- /dev/null +++ b/spec/support/js_test_helpers.rb @@ -0,0 +1,22 @@ +# Test helpers that use javascript +module JSTestHelpers + # uses JS to make a all hidden inputs visible on the page + def js_make_all_inputs_visible + js = " + let ready = (fn) => (document.readyState !== 'loading') + ? fn() + : document.addEventListener('DOMContentLoaded', fn) + + ready(() => + document + .querySelectorAll('input[type=hidden]') + .forEach(input => input.setAttribute('type','text')) + + )" + execute_script(js) + end +end + +RSpec.configure do |config| + config.include JSTestHelpers, type: :feature +end diff --git a/spec/support/utilities.rb b/spec/support/utilities.rb index be9d9b1d..99f5a482 100644 --- a/spec/support/utilities.rb +++ b/spec/support/utilities.rb @@ -4,6 +4,3 @@ def sign_in(user) find('#email').set user.uid click_button 'Sign In' end - - - diff --git a/spec/support/wait_for_ajax.rb b/spec/support/wait_for_ajax.rb index a81aac2a..5ea552cc 100644 --- a/spec/support/wait_for_ajax.rb +++ b/spec/support/wait_for_ajax.rb @@ -7,7 +7,8 @@ def wait_for_ajax end def finished_all_ajax_requests? - page.evaluate_script('jQuery.active').zero? + # only check jQuery.active if jQuery is defined + page.evaluate_script("typeof jQuery !== 'undefined' ? jQuery.active : 0").zero? end end diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..fcdf3861 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6897 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== + dependencies: + "@babel/highlight" "^7.14.5" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" + integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== + +"@babel/core@^7.14.3": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8" + integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@babel/helper-module-transforms" "^7.15.0" + "@babel/helpers" "^7.14.8" + "@babel/parser" "^7.15.0" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15" + integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== + dependencies: + "@babel/types" "^7.15.0" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61" + integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191" + integrity sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818" + integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.16.6" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.14.5": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz#c9a137a4d137b2d0e2c649acf536d7ba1a76c0f7" + integrity sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-split-export-declaration" "^7.14.5" + +"@babel/helper-create-regexp-features-plugin@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4" + integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.2.2": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6" + integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-explode-assignable-expression@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645" + integrity sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4" + integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ== + dependencies: + "@babel/helper-get-function-arity" "^7.14.5" + "@babel/template" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-get-function-arity@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815" + integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-hoist-variables@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d" + integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-member-expression-to-functions@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b" + integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg== + dependencies: + "@babel/types" "^7.15.0" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3" + integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08" + integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-replace-supers" "^7.15.0" + "@babel/helper-simple-access" "^7.14.8" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.9" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/helper-optimise-call-expression@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c" + integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-remap-async-to-generator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6" + integrity sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-wrap-function" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4" + integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.0" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/helper-simple-access@^7.14.8": + version "7.14.8" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924" + integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg== + dependencies: + "@babel/types" "^7.14.8" + +"@babel/helper-skip-transparent-expression-wrappers@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4" + integrity sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-split-export-declaration@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a" + integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA== + dependencies: + "@babel/types" "^7.14.5" + +"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48" + integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== + +"@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== + +"@babel/helper-wrap-function@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff" + integrity sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ== + dependencies: + "@babel/helper-function-name" "^7.14.5" + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/helpers@^7.14.8": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357" + integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g== + dependencies: + "@babel/template" "^7.14.5" + "@babel/traverse" "^7.15.0" + "@babel/types" "^7.15.0" + +"@babel/highlight@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== + dependencies: + "@babel/helper-validator-identifier" "^7.14.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.14.5", "@babel/parser@^7.15.0": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862" + integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e" + integrity sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + +"@babel/plugin-proposal-async-generator-functions@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz#7028dc4fa21dc199bbacf98b39bab1267d0eaf9a" + integrity sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e" + integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz#158e9e10d449c3849ef3ecde94a03d9f1841b681" + integrity sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-dynamic-import@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c" + integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76" + integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb" + integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738" + integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6" + integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18" + integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.14.2", "@babel/plugin-proposal-object-rest-spread@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363" + integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g== + dependencies: + "@babel/compat-data" "^7.14.7" + "@babel/helper-compilation-targets" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.14.5" + +"@babel/plugin-proposal-optional-catch-binding@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c" + integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603" + integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d" + integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-proposal-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636" + integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-create-class-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8" + integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-arrow-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a" + integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-async-to-generator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67" + integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-remap-async-to-generator" "^7.14.5" + +"@babel/plugin-transform-block-scoped-functions@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4" + integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-block-scoping@^7.14.5": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf" + integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-classes@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz#2a391ffb1e5292710b00f2e2c210e1435e7d449f" + integrity sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.14.5" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-optimise-call-expression" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.14.5" + "@babel/helper-split-export-declaration" "^7.14.5" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f" + integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-destructuring@^7.13.17", "@babel/plugin-transform-destructuring@^7.14.7": + version "7.14.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576" + integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a" + integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-duplicate-keys@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954" + integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-exponentiation-operator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493" + integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-for-of@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb" + integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-function-name@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2" + integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ== + dependencies: + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78" + integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-member-expression-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7" + integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-modules-amd@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7" + integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g== + dependencies: + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz#3305896e5835f953b5cdb363acd9e8c2219a5281" + integrity sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig== + dependencies: + "@babel/helper-module-transforms" "^7.15.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-simple-access" "^7.14.8" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz#c75342ef8b30dcde4295d3401aae24e65638ed29" + integrity sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA== + dependencies: + "@babel/helper-hoist-variables" "^7.14.5" + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-identifier" "^7.14.5" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0" + integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA== + dependencies: + "@babel/helper-module-transforms" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9": + version "7.14.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2" + integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + +"@babel/plugin-transform-new-target@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8" + integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-object-super@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45" + integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-replace-supers" "^7.14.5" + +"@babel/plugin-transform-parameters@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3" + integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34" + integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-regenerator@^7.13.15", "@babel/plugin-transform-regenerator@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f" + integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304" + integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-runtime@^7.14.3": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3" + integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw== + dependencies: + "@babel/helper-module-imports" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58" + integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-spread@^7.14.6": + version "7.14.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144" + integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5" + +"@babel/plugin-transform-sticky-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9" + integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-template-literals@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93" + integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-typeof-symbol@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4" + integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-escapes@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b" + integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-transform-unicode-regex@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e" + integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.14.5" + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/preset-env@^7.14.2": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.0.tgz#e2165bf16594c9c05e52517a194bf6187d6fe464" + integrity sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q== + dependencies: + "@babel/compat-data" "^7.15.0" + "@babel/helper-compilation-targets" "^7.15.0" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-async-generator-functions" "^7.14.9" + "@babel/plugin-proposal-class-properties" "^7.14.5" + "@babel/plugin-proposal-class-static-block" "^7.14.5" + "@babel/plugin-proposal-dynamic-import" "^7.14.5" + "@babel/plugin-proposal-export-namespace-from" "^7.14.5" + "@babel/plugin-proposal-json-strings" "^7.14.5" + "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5" + "@babel/plugin-proposal-numeric-separator" "^7.14.5" + "@babel/plugin-proposal-object-rest-spread" "^7.14.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.14.5" + "@babel/plugin-proposal-optional-chaining" "^7.14.5" + "@babel/plugin-proposal-private-methods" "^7.14.5" + "@babel/plugin-proposal-private-property-in-object" "^7.14.5" + "@babel/plugin-proposal-unicode-property-regex" "^7.14.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.14.5" + "@babel/plugin-transform-async-to-generator" "^7.14.5" + "@babel/plugin-transform-block-scoped-functions" "^7.14.5" + "@babel/plugin-transform-block-scoping" "^7.14.5" + "@babel/plugin-transform-classes" "^7.14.9" + "@babel/plugin-transform-computed-properties" "^7.14.5" + "@babel/plugin-transform-destructuring" "^7.14.7" + "@babel/plugin-transform-dotall-regex" "^7.14.5" + "@babel/plugin-transform-duplicate-keys" "^7.14.5" + "@babel/plugin-transform-exponentiation-operator" "^7.14.5" + "@babel/plugin-transform-for-of" "^7.14.5" + "@babel/plugin-transform-function-name" "^7.14.5" + "@babel/plugin-transform-literals" "^7.14.5" + "@babel/plugin-transform-member-expression-literals" "^7.14.5" + "@babel/plugin-transform-modules-amd" "^7.14.5" + "@babel/plugin-transform-modules-commonjs" "^7.15.0" + "@babel/plugin-transform-modules-systemjs" "^7.14.5" + "@babel/plugin-transform-modules-umd" "^7.14.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9" + "@babel/plugin-transform-new-target" "^7.14.5" + "@babel/plugin-transform-object-super" "^7.14.5" + "@babel/plugin-transform-parameters" "^7.14.5" + "@babel/plugin-transform-property-literals" "^7.14.5" + "@babel/plugin-transform-regenerator" "^7.14.5" + "@babel/plugin-transform-reserved-words" "^7.14.5" + "@babel/plugin-transform-shorthand-properties" "^7.14.5" + "@babel/plugin-transform-spread" "^7.14.6" + "@babel/plugin-transform-sticky-regex" "^7.14.5" + "@babel/plugin-transform-template-literals" "^7.14.5" + "@babel/plugin-transform-typeof-symbol" "^7.14.5" + "@babel/plugin-transform-unicode-escapes" "^7.14.5" + "@babel/plugin-transform-unicode-regex" "^7.14.5" + "@babel/preset-modules" "^0.1.4" + "@babel/types" "^7.15.0" + babel-plugin-polyfill-corejs2 "^0.2.2" + babel-plugin-polyfill-corejs3 "^0.2.2" + babel-plugin-polyfill-regenerator "^0.2.2" + core-js-compat "^3.16.0" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.14.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": + version "7.15.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b" + integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4" + integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/parser" "^7.14.5" + "@babel/types" "^7.14.5" + +"@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98" + integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw== + dependencies: + "@babel/code-frame" "^7.14.5" + "@babel/generator" "^7.15.0" + "@babel/helper-function-name" "^7.14.5" + "@babel/helper-hoist-variables" "^7.14.5" + "@babel/helper-split-export-declaration" "^7.14.5" + "@babel/parser" "^7.15.0" + "@babel/types" "^7.15.0" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0", "@babel/types@^7.4.4": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd" + integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ== + dependencies: + "@babel/helper-validator-identifier" "^7.14.9" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + +"@npmcli/move-file@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" + integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== + dependencies: + mkdirp "^1.0.4" + rimraf "^3.0.2" + +"@rails/webpacker@5.4.0": + version "5.4.0" + resolved "https://registry.yarnpkg.com/@rails/webpacker/-/webpacker-5.4.0.tgz#2c64a9ea7e85d2a33e50e86319fe6751df0c47e8" + integrity sha512-J973mzTUJbkbBu+sMwKgWRahoSfwdp5uHT80iDWr6hi8YAC7kj47HapQnn2SGPmv/onTT8WC3jFM62Hkh213yQ== + dependencies: + "@babel/core" "^7.14.3" + "@babel/plugin-proposal-class-properties" "^7.13.0" + "@babel/plugin-proposal-object-rest-spread" "^7.14.2" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.13.17" + "@babel/plugin-transform-regenerator" "^7.13.15" + "@babel/plugin-transform-runtime" "^7.14.3" + "@babel/preset-env" "^7.14.2" + "@babel/runtime" "^7.14.0" + babel-loader "^8.2.2" + babel-plugin-dynamic-import-node "^2.3.3" + babel-plugin-macros "^2.8.0" + case-sensitive-paths-webpack-plugin "^2.4.0" + compression-webpack-plugin "^4.0.1" + core-js "^3.12.1" + css-loader "^3.6.0" + file-loader "^6.2.0" + flatted "^3.1.1" + glob "^7.1.7" + js-yaml "^3.14.1" + mini-css-extract-plugin "^0.9.0" + optimize-css-assets-webpack-plugin "^5.0.6" + path-complete-extname "^1.0.0" + pnp-webpack-plugin "^1.6.4" + postcss-flexbugs-fixes "^4.2.1" + postcss-import "^12.0.1" + postcss-loader "^3.0.0" + postcss-preset-env "^6.7.0" + postcss-safe-parser "^4.0.2" + regenerator-runtime "^0.13.7" + sass "^1.32.13" + sass-loader "10.1.1" + style-loader "^1.3.0" + terser-webpack-plugin "^4.2.3" + webpack "^4.46.0" + webpack-assets-manifest "^3.1.1" + webpack-cli "^3.3.12" + webpack-sources "^1.4.3" + +"@types/glob@^7.1.1": + version "7.1.4" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" + integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": + version "7.0.9" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/minimatch@*": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" + integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== + +"@types/node@*": + version "16.6.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.1.tgz#aee62c7b966f55fc66c7b6dfa1d58db2a616da61" + integrity sha512-Sr7BhXEAer9xyGuCN3Ek9eg9xPviCF2gfu9kTfuU2HkTVAMYSDeX40fvpmo72n5nansg3nsBjuQBrsS28r+NUw== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/q@^1.5.1": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" + integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== + +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== + dependencies: + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + +"@webassemblyjs/floating-point-hex-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== + +"@webassemblyjs/helper-api-error@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== + +"@webassemblyjs/helper-buffer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== + +"@webassemblyjs/helper-code-frame@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== + dependencies: + "@webassemblyjs/wast-printer" "1.9.0" + +"@webassemblyjs/helper-fsm@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== + +"@webassemblyjs/helper-module-context@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== + dependencies: + "@webassemblyjs/ast" "1.9.0" + +"@webassemblyjs/helper-wasm-bytecode@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== + +"@webassemblyjs/helper-wasm-section@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + +"@webassemblyjs/ieee754@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== + +"@webassemblyjs/wasm-edit@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/helper-wasm-section" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-opt" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/wast-printer" "1.9.0" + +"@webassemblyjs/wasm-gen@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + +"@webassemblyjs/wasm-opt@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + +"@webassemblyjs/wasm-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" + +"@webassemblyjs/wast-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/floating-point-hex-parser" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-code-frame" "1.9.0" + "@webassemblyjs/helper-fsm" "1.9.0" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/wast-printer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" + "@xtuc/long" "4.2.2" + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn@^6.4.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv-errors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== + +ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +ansi-colors@^3.0.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" + integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +assert@^1.1.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^9.6.1: + version "9.8.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + colorette "^1.2.1" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +babel-loader@^8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" + integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g== + dependencies: + find-cache-dir "^3.3.1" + loader-utils "^1.4.0" + make-dir "^3.1.0" + schema-utils "^2.6.5" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-macros@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + +babel-plugin-polyfill-corejs2@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" + integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.2.2" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.2.2: + version "0.2.4" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz#68cb81316b0e8d9d721a92e0009ec6ecd4cd2ca9" + integrity sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + core-js-compat "^3.14.0" + +babel-plugin-polyfill-regenerator@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077" + integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.2.2" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.0.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bluebird@^3.5.5: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + +body-parser@1.19.0: + version "1.19.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" + integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== + dependencies: + bytes "3.1.0" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.7.2" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.7.0" + raw-body "2.4.0" + type-is "~1.6.17" + +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU= + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + +boolbase@^1.0.0, boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6, browserslist@^4.16.7, browserslist@^4.6.4: + version "4.16.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.7.tgz#108b0d1ef33c4af1b587c54f390e7041178e4335" + integrity sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA== + dependencies: + caniuse-lite "^1.0.30001248" + colorette "^1.2.2" + electron-to-chromium "^1.3.793" + escalade "^3.1.1" + node-releases "^1.1.73" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^4.3.0: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cacache@^12.0.2: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== + dependencies: + bluebird "^3.5.5" + chownr "^1.1.1" + figgy-pudding "^3.5.1" + glob "^7.1.4" + graceful-fs "^4.1.15" + infer-owner "^1.0.3" + lru-cache "^5.1.1" + mississippi "^3.0.0" + mkdirp "^0.5.1" + move-concurrently "^1.0.1" + promise-inflight "^1.0.1" + rimraf "^2.6.3" + ssri "^6.0.1" + unique-filename "^1.1.1" + y18n "^4.0.0" + +cacache@^15.0.5: + version "15.2.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.2.0.tgz#73af75f77c58e72d8c630a7a2858cb18ef523389" + integrity sha512-uKoJSHmnrqXgthDFx/IU6ED/5xd+NNGe+Bb+kLZy7Ku4P+BaiWEUflAKPZ7eAzsYGcsAGASJZsybXp+quEcHTw== + dependencies: + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +caller-callsite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" + integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= + dependencies: + callsites "^2.0.0" + +caller-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" + integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= + dependencies: + caller-callsite "^2.0.0" + +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001248: + version "1.0.30001251" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz#6853a606ec50893115db660f82c094d18f096d85" + integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A== + +case-sensitive-paths-webpack-plugin@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4" + integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw== + +chalk@^2.0, chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +chrome-trace-event@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312" + integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorette@^1.2.1, colorette@^1.2.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af" + integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression-webpack-plugin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/compression-webpack-plugin/-/compression-webpack-plugin-4.0.1.tgz#33eda97f1170dd38c5556771de10f34245aa0274" + integrity sha512-0mg6PgwTsUe5LEcUrOu3ob32vraDx2VdbMGAT1PARcOV+UJWDYZFdkSo6RbHoGQ061mmmkC7XpRKOlvwm/gzJQ== + dependencies: + cacache "^15.0.5" + find-cache-dir "^3.3.1" + schema-utils "^2.7.0" + serialize-javascript "^4.0.0" + webpack-sources "^1.4.3" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +connect-history-api-fallback@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +content-disposition@0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" + integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== + dependencies: + safe-buffer "5.1.2" + +content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" + integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== + +copy-concurrently@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== + dependencies: + aproba "^1.1.1" + fs-write-stream-atomic "^1.0.8" + iferr "^0.1.5" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.0" + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.14.0, core-js-compat@^3.16.0: + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.2.tgz#442ef1d933ca6fc80859bd5a1db7a3ba716aaf56" + integrity sha512-4lUshXtBXsdmp8cDWh6KKiHUg40AjiuPD3bOWkNVsr1xkAhpUqCjaZ8lB1bKx9Gb5fXcbRbFJ4f4qpRIRTuJqQ== + dependencies: + browserslist "^4.16.7" + semver "7.0.0" + +core-js@^3.12.1: + version "3.16.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.2.tgz#3f485822889c7fc48ef463e35be5cc2a4a01a1f4" + integrity sha512-P0KPukO6OjMpjBtHSceAZEWlDD1M2Cpzpg6dBbrjFqFhBHe/BwhxaP820xKOjRn/lZRQirrCusIpLS/n2sgXLQ== + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cosmiconfig@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" + integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== + dependencies: + import-fresh "^2.0.0" + is-directory "^0.3.1" + js-yaml "^3.13.1" + parse-json "^4.0.0" + +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== + dependencies: + postcss "^7.0.5" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +css-loader@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" + integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.32" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.2.0" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.1.0" + schema-utils "^2.7.0" + semver "^6.3.0" + +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== + +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== + dependencies: + mdn-data "2.0.14" + source-map "^0.6.1" + +css-what@^3.2.1: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4" + integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ== + +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +cssnano-preset-default@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.8.tgz#920622b1fc1e95a34e8838203f1397a504f2d3ff" + integrity sha512-LdAyHuq+VRyeVREFmuxUZR1TXjQm8QQU/ktoo/x7bz+SdOge1YKc5eMN6pRW7YWBmyq59CqYba1dJ5cUukEjLQ== + dependencies: + css-declaration-sorter "^4.0.1" + cssnano-util-raw-cache "^4.0.1" + postcss "^7.0.0" + postcss-calc "^7.0.1" + postcss-colormin "^4.0.3" + postcss-convert-values "^4.0.1" + postcss-discard-comments "^4.0.2" + postcss-discard-duplicates "^4.0.2" + postcss-discard-empty "^4.0.1" + postcss-discard-overridden "^4.0.1" + postcss-merge-longhand "^4.0.11" + postcss-merge-rules "^4.0.3" + postcss-minify-font-values "^4.0.2" + postcss-minify-gradients "^4.0.2" + postcss-minify-params "^4.0.2" + postcss-minify-selectors "^4.0.2" + postcss-normalize-charset "^4.0.1" + postcss-normalize-display-values "^4.0.2" + postcss-normalize-positions "^4.0.2" + postcss-normalize-repeat-style "^4.0.2" + postcss-normalize-string "^4.0.2" + postcss-normalize-timing-functions "^4.0.2" + postcss-normalize-unicode "^4.0.1" + postcss-normalize-url "^4.0.1" + postcss-normalize-whitespace "^4.0.2" + postcss-ordered-values "^4.1.2" + postcss-reduce-initial "^4.0.3" + postcss-reduce-transforms "^4.0.2" + postcss-svgo "^4.0.3" + postcss-unique-selectors "^4.0.1" + +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= + +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.11" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.11.tgz#c7b5f5b81da269cb1fd982cb960c1200910c9a99" + integrity sha512-6gZm2htn7xIPJOHY824ERgj8cNPgPxyCSnkXc4v7YvNW+TdVfzgngHcEhy/8D11kUWRUMbke+tC+AUcUsnMz2g== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.8" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.2.0" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== + dependencies: + css-tree "^1.1.2" + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^3.1.1, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" + integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== + dependencies: + ms "2.1.2" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +default-gateway@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" + integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA== + dependencies: + execa "^1.0.0" + ip-regex "^2.1.0" + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +del@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4" + integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ== + dependencies: + "@types/glob" "^7.1.1" + globby "^6.1.0" + is-path-cwd "^2.0.0" + is-path-in-cwd "^2.0.0" + p-map "^2.0.0" + pify "^4.0.1" + rimraf "^2.6.3" + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0= + +dns-packet@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f" + integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA== + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + +dom-serializer@0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" + integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== + dependencies: + domelementtype "^2.0.1" + entities "^2.0.0" + +domain-browser@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domelementtype@1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" + integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== + +domelementtype@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== + +domutils@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" + integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== + dependencies: + dom-serializer "0" + domelementtype "1" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +duplexify@^3.4.2, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.793: + version "1.3.808" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.808.tgz#6aa204f56c6de554cd4e90e1eb1a36f3ac3a15d5" + integrity sha512-espnsbWTuUw0a2jMwfabCc09py2ujB+FZZE1hZWn5yYijEmxzEhdhTLKUfZGjynHvdIMQ4X/Pr/t8s4eiyH/QQ== + +elliptic@^6.5.3: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" + integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + +entities@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" + integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== + +errno@^0.1.3, errno@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.2, es-abstract@^1.18.0-next.2, es-abstract@^1.18.2: + version "1.18.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19" + integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.3" + is-negative-zero "^2.0.1" + is-regex "^1.1.3" + is-string "^1.0.6" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +eslint-scope@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esrecurse@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +eventsource@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.0.tgz#00e8ca7c92109e94b0ddf32dac677d841028cfaf" + integrity sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg== + dependencies: + original "^1.0.0" + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +express@^4.17.1: + version "4.17.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" + integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.0" + content-disposition "0.5.3" + content-type "~1.0.4" + cookie "0.4.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.5" + qs "6.7.0" + range-parser "~1.2.1" + safe-buffer "5.1.2" + send "0.17.1" + serve-static "1.14.1" + setprototypeof "1.1.1" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +figgy-pudding@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +file-loader@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== + dependencies: + loader-utils "^2.0.0" + schema-utils "^3.0.0" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-cache-dir@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880" + integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== + dependencies: + commondir "^1.0.1" + make-dir "^3.0.2" + pkg-dir "^4.1.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +findup-sync@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +flatted@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" + integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== + +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + +flush-write-stream@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@^1.0.0: + version "1.14.8" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc" + integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA== + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +from2@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-write-stream-atomic@^1.0.8: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= + dependencies: + graceful-fs "^4.1.2" + iferr "^0.1.5" + imurmurhash "^0.1.4" + readable-stream "1 || 2" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.0.3, glob@^7.1.3, glob@^7.1.4, glob@^7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw= + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: + version "4.2.8" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI= + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= + +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-entities@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.4.0.tgz#cfbd1b01d2afaf9adca1b10ae7dffab98c71d2dc" + integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc= + +http-errors@1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" + integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-parser-js@>=0.5.1: + version "0.5.3" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" + integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== + +http-proxy-middleware@0.19.1: + version "0.19.1" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" + integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q== + dependencies: + http-proxy "^1.17.0" + is-glob "^4.0.0" + lodash "^4.17.11" + micromatch "^3.1.10" + +http-proxy@^1.17.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +icss-utils@^4.0.0, icss-utils@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" + integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== + dependencies: + postcss "^7.0.14" + +ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +iferr@^0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= + +import-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" + integrity sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk= + dependencies: + import-from "^2.1.0" + +import-fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" + integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= + dependencies: + caller-path "^2.0.0" + resolve-from "^3.0.0" + +import-fresh@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-from@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/import-from/-/import-from-2.1.0.tgz#335db7f2a7affd53aaa471d4b8021dee36b7f3b1" + integrity sha1-M1238qev/VOqpHHUuAId7ja387E= + dependencies: + resolve-from "^3.0.0" + +import-local@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" + integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== + dependencies: + pkg-dir "^3.0.0" + resolve-cwd "^2.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= + +infer-owner@^1.0.3, infer-owner@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4, ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-ip@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" + integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg== + dependencies: + default-gateway "^4.2.0" + ipaddr.js "^1.9.0" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +interpret@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +ip@^1.1.0, ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + +is-absolute-url@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.4, is-callable@^1.2.3: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" + +is-core-module@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.5.0.tgz#f754843617c70bfd29b7bd87327400cda5c18491" + integrity sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-negative-zero@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" + integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-cwd@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-in-cwd@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb" + integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ== + dependencies: + is-path-inside "^2.1.0" + +is-path-inside@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2" + integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg== + dependencies: + path-is-inside "^1.0.2" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4, is-regex@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-string@^1.0.5, is-string@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +jest-worker@^26.5.0: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1, js-yaml@^3.14.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json3@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" + integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +killable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" + integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +klona@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" + integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== + +last-call-webpack-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" + integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== + dependencies: + lodash "^4.17.5" + webpack-sources "^1.1.0" + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +loader-runner@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== + +loader-utils@^1.1.0, loader-utils@^1.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" + +loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.get@^4.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + +lodash.has@^4.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862" + integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI= + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.5: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loglevel@^1.6.8: + version "1.7.1" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" + integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.2, make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +memory-fs@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.49.0, "mime-db@>= 1.43.0 < 2": + version "1.49.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" + integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== + +mime-types@~2.1.17, mime-types@~2.1.24: + version "2.1.32" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" + integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== + dependencies: + mime-db "1.49.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.4.4: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== + +mini-css-extract-plugin@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz#47f2cf07aa165ab35733b1fc97d4c46c0564339e" + integrity sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A== + dependencies: + loader-utils "^1.1.0" + normalize-url "1.9.1" + schema-utils "^1.0.0" + webpack-sources "^1.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minipass-collect@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== + dependencies: + minipass "^3.0.0" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.2: + version "1.2.4" + resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0, minipass@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" + integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mississippi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== + dependencies: + concat-stream "^1.5.0" + duplexify "^3.4.2" + end-of-stream "^1.1.0" + flush-write-stream "^1.0.0" + from2 "^2.1.0" + parallel-transform "^1.1.0" + pump "^3.0.0" + pumpify "^1.3.3" + stream-each "^1.1.0" + through2 "^2.0.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +move-concurrently@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= + dependencies: + aproba "^1.1.1" + copy-concurrently "^1.0.0" + fs-write-stream-atomic "^1.0.8" + mkdirp "^0.5.1" + rimraf "^2.5.4" + run-queue "^1.0.3" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE= + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g== + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + +nan@^2.12.1: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-forge@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" + integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== + +node-libs-browser@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== + dependencies: + assert "^1.1.1" + browserify-zlib "^0.2.0" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^3.0.0" + https-browserify "^1.0.0" + os-browserify "^0.3.0" + path-browserify "0.0.1" + process "^0.11.10" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.3.3" + stream-browserify "^2.0.1" + stream-http "^2.7.2" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.11.0" + vm-browserify "^1.0.1" + +node-releases@^1.1.73: + version "1.1.74" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.74.tgz#e5866488080ebaa70a93b91144ccde06f3c3463e" + integrity sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw== + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +normalize-url@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + integrity sha1-LMDWazHqIwNkWENuNiDYWVTGbDw= + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +nth-check@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" + integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1" + integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7" + integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.values@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.4.tgz#0d273762833e816b693a637d30073e7051535b30" + integrity sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +opn@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" + +optimize-css-assets-webpack-plugin@^5.0.6: + version "5.0.8" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.8.tgz#cbccdcf5a6ef61d4f8cc78cf083a67446e5f402a" + integrity sha512-mgFS1JdOtEGzD8l+EuISqL57cKO+We9GcoiQEmdCWRqqck+FGNmYJtx9qfAPzEz+lRrlThWMuGDaRkI/yWNx/Q== + dependencies: + cssnano "^4.1.10" + last-call-webpack-plugin "^3.0.0" + +original@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" + integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + dependencies: + url-parse "^1.4.3" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-retry@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" + integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w== + dependencies: + retry "^0.12.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parallel-transform@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== + dependencies: + cyclist "^1.0.1" + inherits "^2.0.3" + readable-stream "^2.1.5" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + +parse-json@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== + +path-complete-extname@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/path-complete-extname/-/path-complete-extname-1.0.0.tgz#f889985dc91000c815515c0bfed06c5acda0752b" + integrity sha512-CVjiWcMRdGU8ubs08YQVzhutOR5DEfO97ipRIlOGMK5Bek5nQySknBpuxVAVJ36hseTNs+vdIcv57ZrWxH7zvg== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-is-inside@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-parse@^1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pnp-webpack-plugin@^1.6.4: + version "1.7.0" + resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz#65741384f6d8056f36e2255a8d67ffc20866f5c9" + integrity sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg== + dependencies: + ts-pnp "^1.1.6" + +portfinder@^1.0.26: + version "1.0.28" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778" + integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.5" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + +postcss-calc@^7.0.1: + version "7.0.5" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.5.tgz#f8a6e99f12e619c2ebc23cf6c486fdc15860933e" + integrity sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg== + dependencies: + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-flexbugs-fixes@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-4.2.1.tgz#9218a65249f30897deab1033aced8578562a6690" + integrity sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ== + dependencies: + postcss "^7.0.26" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.1.tgz#42d4c0ab30894f60f98b17561eb5c0321f502641" + integrity sha512-I3ADQSTNtLTTd8uxZhtSOrTCQ9G4qUVKPjHiDk0bV75QSxXjVWiJVJ2VLdspGUi9fbW9BcjKJoRvxAH1pckqmA== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-import@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-12.0.1.tgz#cf8c7ab0b5ccab5649024536e565f841928b7153" + integrity sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw== + dependencies: + postcss "^7.0.1" + postcss-value-parser "^3.2.3" + read-cache "^1.0.0" + resolve "^1.1.7" + +postcss-initial@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.4.tgz#9d32069a10531fe2ecafa0b6ac750ee0bc7efc53" + integrity sha512-3RLn6DIpMsK1l5UUy9jxQvoDeUN4gP939tDcKUHD/kM8SGSKbFAnvkpFpj3Bhtz3HGk1jWY5ZNWX6mPta5M9fg== + dependencies: + postcss "^7.0.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-load-config@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a" + integrity sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw== + dependencies: + cosmiconfig "^5.0.0" + import-cwd "^2.0.0" + +postcss-loader@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" + integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== + dependencies: + loader-utils "^1.1.0" + postcss "^7.0.0" + postcss-load-config "^2.0.0" + schema-utils "^1.0.0" + +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + alphanum-sort "^1.0.0" + browserslist "^4.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +postcss-modules-extract-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" + integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ== + dependencies: + postcss "^7.0.5" + +postcss-modules-local-by-default@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz#bb14e0cc78279d504dbdcbfd7e0ca28993ffbbb0" + integrity sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw== + dependencies: + icss-utils "^4.1.1" + postcss "^7.0.32" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" + integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + +postcss-nesting@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-overflow-shorthand@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== + dependencies: + postcss "^7.0.2" + +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + autoprefixer "^9.6.1" + browserslist "^4.6.4" + caniuse-lite "^1.0.30000981" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.4.0" + postcss "^7.0.17" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.3" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.8" + postcss-custom-properties "^8.0.11" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-safe-parser@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" + integrity sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g== + dependencies: + postcss "^7.0.26" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.1.tgz#263016eef1cf219e0ade9a913780fc1f48204cbf" + integrity sha512-YolvBgInEK5/79C+bdFMyzqTg6pkYqDbzZIST/PDMqa/o3qtXenD05apBG2jLgT0/BQ77d4U2UK12jWpilqMAQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== + dependencies: + dot-prop "^5.2.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: + version "6.0.6" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-svgo@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e" + integrity sha512-NoRbrcMWTtUghzuKSoIm6XV+sJdvZ7GZSc3wdBN0W19FTtp2ko8NqLsgoh/m9CzNhU3KLPvQmjIwtaNFkaFTvw== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.2.3: + version "3.3.1" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" + integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== + +postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.36" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.36.tgz#056f8cffa939662a8f5905950c07d5285644dfcb" + integrity sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise-inflight@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= + +proxy-addr@~2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" + integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" + integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== + dependencies: + bytes "3.1.0" + http-errors "1.7.2" + iconv-lite "0.4.24" + unpipe "1.0.0" + +read-cache@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" + integrity sha1-5mTvMRYRZsl1HNvo28+GtftY93Q= + dependencies: + pify "^2.3.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.7: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + integrity sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +regexpu-core@^4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" + integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.6.4: + version "0.6.9" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6" + integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ== + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.7, resolve@^1.12.0, resolve@^1.14.2: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +run-queue@^1.0.0, run-queue@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= + dependencies: + aproba "^1.1.1" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass-loader@10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.1.1.tgz#4ddd5a3d7638e7949065dd6e9c7c04037f7e663d" + integrity sha512-W6gVDXAd5hR/WHsPicvZdjAWHBcEJ44UahgxcIE196fW2ong0ZHMPO1kZuI5q0VlvMQZh32gpv69PLWQm70qrw== + dependencies: + klona "^2.0.4" + loader-utils "^2.0.0" + neo-async "^2.6.2" + schema-utils "^3.0.0" + semver "^7.3.2" + +sass@^1.32.13: + version "1.38.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.38.0.tgz#2f3e60a1efdcdc910586fa79dc89d3399a145b4f" + integrity sha512-WBccZeMigAGKoI+NgD7Adh0ab1HUq+6BmyBUEaGxtErbUtWUevEbdgo5EZiJQofLUGcKtlNaO2IdN73AHEua5g== + dependencies: + chokidar ">=3.0.0 <4.0.0" + +sax@~1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +schema-utils@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== + dependencies: + ajv "^6.1.0" + ajv-errors "^1.0.0" + ajv-keywords "^3.1.0" + +schema-utils@^2.6.5, schema-utils@^2.7.0: + version "2.7.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7" + integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg== + dependencies: + "@types/json-schema" "^7.0.5" + ajv "^6.12.4" + ajv-keywords "^3.5.2" + +schema-utils@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= + +selfsigned@^1.10.8: + version "1.10.11" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9" + integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA== + dependencies: + node-forge "^0.10.0" + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serialize-javascript@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" + integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.14.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +sockjs-client@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.5.1.tgz#256908f6d5adfb94dabbdbd02c66362cca0f9ea6" + integrity sha512-VnVAb663fosipI/m6pqRXakEOw7nvd7TUgdr3PlR/8V2I95QIdwT8L4nMxhyU8SmDBHYXU1TOElaKOmKLfYzeQ== + dependencies: + debug "^3.2.6" + eventsource "^1.0.7" + faye-websocket "^0.11.3" + inherits "^2.0.4" + json3 "^3.3.3" + url-parse "^1.5.1" + +sockjs@^0.3.21: + version "0.3.21" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417" + integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw== + dependencies: + faye-websocket "^0.11.3" + uuid "^3.4.0" + websocket-driver "^0.7.4" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@~0.5.12, source-map-support@~0.5.19: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.7.2: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +ssri@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" + integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== + dependencies: + figgy-pudding "^3.5.1" + +ssri@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== + dependencies: + minipass "^3.1.1" + +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +stream-browserify@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-each@^1.1.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== + dependencies: + end-of-stream "^1.1.0" + stream-shift "^1.0.0" + +stream-http@^2.7.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.3.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +style-loader@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.3.0.tgz#828b4a3b3b7e7aa5847ce7bae9e874512114249e" + integrity sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q== + dependencies: + loader-utils "^2.0.0" + schema-utils "^2.7.0" + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +svgo@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +tapable@^1.0.0, tapable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== + +tar@^6.0.2: + version "6.1.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.8.tgz#4fc50cfe56511c538ce15b71e05eebe66530cbd4" + integrity sha512-sb9b0cp855NbkMJcskdSYA7b11Q8JsX4qe4pyUAfHp+Y6jBjJeek2ZVlwEfWayshEIwlIzXx0Fain3QG9JPm2A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +terser-webpack-plugin@^1.4.3: + version "1.4.5" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" + integrity sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw== + dependencies: + cacache "^12.0.2" + find-cache-dir "^2.1.0" + is-wsl "^1.1.0" + schema-utils "^1.0.0" + serialize-javascript "^4.0.0" + source-map "^0.6.1" + terser "^4.1.2" + webpack-sources "^1.4.0" + worker-farm "^1.7.0" + +terser-webpack-plugin@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.3.tgz#28daef4a83bd17c1db0297070adc07fc8cfc6a9a" + integrity sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ== + dependencies: + cacache "^15.0.5" + find-cache-dir "^3.3.1" + jest-worker "^26.5.0" + p-limit "^3.0.2" + schema-utils "^3.0.0" + serialize-javascript "^5.0.1" + source-map "^0.6.1" + terser "^5.3.4" + webpack-sources "^1.4.3" + +terser@^4.1.2: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +terser@^5.3.4: + version "5.7.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" + integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + +through2@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +ts-pnp@^1.1.6: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" + integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= + +type-is@~1.6.17, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + +unique-filename@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== + dependencies: + unique-slug "^2.0.0" + +unique-slug@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== + dependencies: + imurmurhash "^0.1.4" + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url-parse@^1.4.3, url-parse@^1.5.1: + version "1.5.3" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862" + integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== + dependencies: + inherits "2.0.3" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +v8-compile-cache@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +watchpack-chokidar2@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" + integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== + dependencies: + chokidar "^2.1.8" + +watchpack@^1.7.4: + version "1.7.5" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" + integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== + dependencies: + graceful-fs "^4.1.2" + neo-async "^2.5.0" + optionalDependencies: + chokidar "^3.4.1" + watchpack-chokidar2 "^2.0.1" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webpack-assets-manifest@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/webpack-assets-manifest/-/webpack-assets-manifest-3.1.1.tgz#39bbc3bf2ee57fcd8ba07cda51c9ba4a3c6ae1de" + integrity sha512-JV9V2QKc5wEWQptdIjvXDUL1ucbPLH2f27toAY3SNdGZp+xSaStAgpoMcvMZmqtFrBc9a5pTS1058vxyMPOzRQ== + dependencies: + chalk "^2.0" + lodash.get "^4.0" + lodash.has "^4.0" + mkdirp "^0.5" + schema-utils "^1.0.0" + tapable "^1.0.0" + webpack-sources "^1.0.0" + +webpack-cli@^3.3.12: + version "3.3.12" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" + integrity sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag== + dependencies: + chalk "^2.4.2" + cross-spawn "^6.0.5" + enhanced-resolve "^4.1.1" + findup-sync "^3.0.0" + global-modules "^2.0.0" + import-local "^2.0.0" + interpret "^1.4.0" + loader-utils "^1.4.0" + supports-color "^6.1.0" + v8-compile-cache "^2.1.1" + yargs "^13.3.2" + +webpack-dev-middleware@^3.7.2: + version "3.7.3" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" + integrity sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ== + dependencies: + memory-fs "^0.4.1" + mime "^2.4.4" + mkdirp "^0.5.1" + range-parser "^1.2.1" + webpack-log "^2.0.0" + +webpack-dev-server@^3.11.2: + version "3.11.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.11.2.tgz#695ebced76a4929f0d5de7fd73fafe185fe33708" + integrity sha512-A80BkuHRQfCiNtGBS1EMf2ChTUs0x+B3wGDFmOeT4rmJOHhHTCH2naNxIHhmkr0/UillP4U3yeIyv1pNp+QDLQ== + dependencies: + ansi-html "0.0.7" + bonjour "^3.5.0" + chokidar "^2.1.8" + compression "^1.7.4" + connect-history-api-fallback "^1.6.0" + debug "^4.1.1" + del "^4.1.1" + express "^4.17.1" + html-entities "^1.3.1" + http-proxy-middleware "0.19.1" + import-local "^2.0.0" + internal-ip "^4.3.0" + ip "^1.1.5" + is-absolute-url "^3.0.3" + killable "^1.0.1" + loglevel "^1.6.8" + opn "^5.5.0" + p-retry "^3.0.1" + portfinder "^1.0.26" + schema-utils "^1.0.0" + selfsigned "^1.10.8" + semver "^6.3.0" + serve-index "^1.9.1" + sockjs "^0.3.21" + sockjs-client "^1.5.0" + spdy "^4.0.2" + strip-ansi "^3.0.1" + supports-color "^6.1.0" + url "^0.11.0" + webpack-dev-middleware "^3.7.2" + webpack-log "^2.0.0" + ws "^6.2.1" + yargs "^13.3.2" + +webpack-log@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f" + integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg== + dependencies: + ansi-colors "^3.0.0" + uuid "^3.3.2" + +webpack-sources@^1.0.0, webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== + dependencies: + source-list-map "^2.0.0" + source-map "~0.6.1" + +webpack@^4.46.0: + version "4.46.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" + integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/wasm-edit" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + acorn "^6.4.1" + ajv "^6.10.2" + ajv-keywords "^3.4.1" + chrome-trace-event "^1.0.2" + enhanced-resolve "^4.5.0" + eslint-scope "^4.0.3" + json-parse-better-errors "^1.0.2" + loader-runner "^2.4.0" + loader-utils "^1.2.3" + memory-fs "^0.4.1" + micromatch "^3.1.10" + mkdirp "^0.5.3" + neo-async "^2.6.1" + node-libs-browser "^2.2.1" + schema-utils "^1.0.0" + tapable "^1.1.3" + terser-webpack-plugin "^1.4.3" + watchpack "^1.7.4" + webpack-sources "^1.4.1" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@^1.2.14, which@^1.2.9, which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +worker-farm@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== + dependencies: + errno "~0.1.7" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +ws@^6.2.1: + version "6.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" + integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw== + dependencies: + async-limiter "~1.0.0" + +xtend@^4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==