]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Merge pull request #1540 from ArthurHoaro/fix/metadata-regexes
authorArthurHoaro <arthur@hoa.ro>
Tue, 13 Oct 2020 10:26:55 +0000 (12:26 +0200)
committerGitHub <noreply@github.com>
Tue, 13 Oct 2020 10:26:55 +0000 (12:26 +0200)
Improve regex to extract HTML metadata (title, description, etc.)

231 files changed:
.dev/.sasslintrc [deleted file]
.dev/.stylelintrc.js [new file with mode: 0644]
.github/mailmap
.htaccess
.travis.yml
AUTHORS
CHANGELOG.md
Makefile
README.md
application/Utils.php
application/api/ApiMiddleware.php
application/api/ApiUtils.php
application/api/controllers/ApiController.php
application/api/controllers/Links.php
application/bookmark/BookmarkFileService.php
application/bookmark/BookmarkFilter.php
application/bookmark/BookmarkInitializer.php
application/bookmark/LinkUtils.php
application/config/ConfigJson.php
application/container/ContainerBuilder.php
application/container/ShaarliContainer.php
application/feed/FeedBuilder.php
application/formatter/BookmarkFormatter.php
application/formatter/BookmarkMarkdownExtraFormatter.php [new file with mode: 0644]
application/front/controller/admin/ConfigureController.php
application/front/controller/admin/ManageShaareController.php
application/front/controller/admin/ManageTagController.php
application/front/controller/admin/PluginsController.php
application/front/controller/admin/ShaarliAdminController.php
application/front/controller/visitor/BookmarkListController.php
application/front/controller/visitor/DailyController.php
application/front/controller/visitor/ErrorNotFoundController.php [new file with mode: 0644]
application/front/controller/visitor/FeedController.php
application/front/controller/visitor/ShaarliVisitorController.php
application/front/controller/visitor/TagCloudController.php
application/http/HttpUtils.php
application/legacy/LegacyController.php
application/legacy/LegacyRouter.php
application/plugin/PluginManager.php
application/render/PageBuilder.php
assets/default/js/base.js
assets/default/scss/shaarli.scss
assets/vintage/css/shaarli.css
composer.json
composer.lock
doc/md/3rd-party-libraries.md [deleted file]
doc/md/Backup-and-restore.md [new file with mode: 0644]
doc/md/Browsing-and-searching.md [deleted file]
doc/md/Community-and-related-software.md [moved from doc/md/Community-&-Related-software.md with 74% similarity]
doc/md/Continuous-integration-tools.md [deleted file]
doc/md/Development-guidelines.md [deleted file]
doc/md/Directory-structure.md [deleted file]
doc/md/Docker.md [new file with mode: 0644]
doc/md/Download-and-Installation.md [deleted file]
doc/md/FAQ.md [deleted file]
doc/md/Installation.md [new file with mode: 0644]
doc/md/Link-structure.md [deleted file]
doc/md/Plugins.md
doc/md/REST-API.md
doc/md/RSS-feeds.md [deleted file]
doc/md/Release-Shaarli.md [deleted file]
doc/md/Reverse-proxy.md [new file with mode: 0644]
doc/md/Security.md [deleted file]
doc/md/Server-configuration.md
doc/md/Server-security.md [deleted file]
doc/md/Shaarli-configuration.md
doc/md/Sharing-content.md [deleted file]
doc/md/Static-analysis.md [deleted file]
doc/md/Troubleshooting.md
doc/md/Unit-tests.md [deleted file]
doc/md/Upgrade-and-migration.md
doc/md/Usage.md [new file with mode: 0644]
doc/md/dev/Development.md [new file with mode: 0644]
doc/md/dev/GnuPG-signature.md [moved from doc/md/GnuPG-signature.md with 66% similarity]
doc/md/dev/Plugin-system.md [moved from doc/md/Plugin-System.md with 83% similarity]
doc/md/dev/Release-Shaarli.md [new file with mode: 0644]
doc/md/dev/Theming.md [moved from doc/md/Theming.md with 95% similarity]
doc/md/dev/Translations.md [moved from doc/md/Translations.md with 66% similarity]
doc/md/dev/Unit-tests.md [new file with mode: 0644]
doc/md/dev/Versioning.md [moved from doc/md/Versioning-and-Branches.md with 58% similarity]
doc/md/dev/images/poedit-1.jpg [moved from doc/md/images/poedit-1.jpg with 100% similarity]
doc/md/docker/docker-101.md [deleted file]
doc/md/docker/resources.md [deleted file]
doc/md/docker/reverse-proxy-configuration.md [deleted file]
doc/md/docker/shaarli-images.md [deleted file]
doc/md/guides/backup-restore-import-export.md [deleted file]
doc/md/guides/images/01-create-droplet-distro.jpg [deleted file]
doc/md/guides/images/02-create-droplet-region.jpg [deleted file]
doc/md/guides/images/03-create-droplet-size.jpg [deleted file]
doc/md/guides/images/04-finalize.jpg [deleted file]
doc/md/guides/images/05-droplet.jpg [deleted file]
doc/md/guides/images/06-domain.jpg [deleted file]
doc/md/guides/install-shaarli-with-debian9-and-docker.md [deleted file]
doc/md/guides/various-hacks.md [deleted file]
doc/md/images/07-installation.jpg [moved from doc/md/guides/images/07-installation.jpg with 100% similarity]
doc/md/images/bookmarklet.png [deleted file]
doc/md/images/firefoxshare.png [deleted file]
doc/md/images/install-shaarli.png [deleted file]
doc/md/index.md
docker-compose.yml
inc/languages/fr/LC_MESSAGES/shaarli.po
index.php
mkdocs.yml
package.json
plugins/archiveorg/archiveorg.php
plugins/isso/isso.php
plugins/playvideos/README.md
plugins/qrcode/qrcode.php
tests/ApplicationUtilsTest.php
tests/FileUtilsTest.php
tests/HistoryTest.php
tests/LanguagesTest.php
tests/PluginManagerTest.php
tests/TestCase.php [new file with mode: 0644]
tests/ThumbnailerTest.php
tests/TimeZoneTest.php
tests/UtilsTest.php
tests/api/ApiMiddlewareTest.php
tests/api/ApiUtilsTest.php
tests/api/controllers/history/HistoryTest.php
tests/api/controllers/info/InfoTest.php
tests/api/controllers/links/DeleteLinkTest.php
tests/api/controllers/links/GetLinkIdTest.php
tests/api/controllers/links/GetLinksTest.php
tests/api/controllers/links/PostLinkTest.php
tests/api/controllers/links/PutLinkTest.php
tests/api/controllers/tags/DeleteTagTest.php
tests/api/controllers/tags/GetTagNameTest.php
tests/api/controllers/tags/GetTagsTest.php
tests/api/controllers/tags/PutTagTest.php
tests/bookmark/BookmarkArrayTest.php
tests/bookmark/BookmarkFileServiceTest.php
tests/bookmark/BookmarkFilterTest.php
tests/bookmark/BookmarkInitializerTest.php
tests/bookmark/BookmarkTest.php
tests/bookmark/LinkUtilsTest.php
tests/bootstrap.php
tests/config/ConfigJsonTest.php
tests/config/ConfigManagerTest.php
tests/config/ConfigPhpTest.php
tests/config/ConfigPluginTest.php
tests/container/ContainerBuilderTest.php
tests/feed/CachedPageTest.php
tests/feed/FeedBuilderTest.php
tests/formatter/BookmarkDefaultFormatterTest.php
tests/formatter/BookmarkMarkdownExtraFormatterTest.php [new file with mode: 0644]
tests/formatter/BookmarkMarkdownFormatterTest.php
tests/formatter/BookmarkRawFormatterTest.php
tests/formatter/FormatterFactoryTest.php
tests/front/ShaarliAdminMiddlewareTest.php
tests/front/ShaarliMiddlewareTest.php
tests/front/controller/admin/ConfigureControllerTest.php
tests/front/controller/admin/ExportControllerTest.php
tests/front/controller/admin/ImportControllerTest.php
tests/front/controller/admin/LogoutControllerTest.php
tests/front/controller/admin/ManageShaareControllerTest/AddShaareTest.php
tests/front/controller/admin/ManageShaareControllerTest/ChangeVisibilityBookmarkTest.php
tests/front/controller/admin/ManageShaareControllerTest/DeleteBookmarkTest.php
tests/front/controller/admin/ManageShaareControllerTest/DisplayCreateFormTest.php
tests/front/controller/admin/ManageShaareControllerTest/DisplayEditFormTest.php
tests/front/controller/admin/ManageShaareControllerTest/PinBookmarkTest.php
tests/front/controller/admin/ManageShaareControllerTest/SaveBookmarkTest.php
tests/front/controller/admin/ManageTagControllerTest.php
tests/front/controller/admin/PasswordControllerTest.php
tests/front/controller/admin/PluginsControllerTest.php
tests/front/controller/admin/SessionFilterControllerTest.php
tests/front/controller/admin/ShaarliAdminControllerTest.php
tests/front/controller/admin/ThumbnailsControllerTest.php
tests/front/controller/admin/TokenControllerTest.php
tests/front/controller/admin/ToolsControllerTest.php
tests/front/controller/visitor/BookmarkListControllerTest.php
tests/front/controller/visitor/DailyControllerTest.php
tests/front/controller/visitor/ErrorControllerTest.php
tests/front/controller/visitor/ErrorNotFoundControllerTest.php [new file with mode: 0644]
tests/front/controller/visitor/FeedControllerTest.php
tests/front/controller/visitor/FrontControllerMockHelper.php
tests/front/controller/visitor/InstallControllerTest.php
tests/front/controller/visitor/LoginControllerTest.php
tests/front/controller/visitor/OpenSearchControllerTest.php
tests/front/controller/visitor/PictureWallControllerTest.php
tests/front/controller/visitor/PublicSessionFilterControllerTest.php
tests/front/controller/visitor/ShaarliVisitorControllerTest.php
tests/front/controller/visitor/TagCloudControllerTest.php
tests/front/controller/visitor/TagControllerTest.php
tests/http/HttpUtils/ClientIpIdTest.php
tests/http/HttpUtils/GetHttpUrlTest.php
tests/http/HttpUtils/GetIpAdressFromProxyTest.php
tests/http/HttpUtils/IndexUrlTest.php
tests/http/HttpUtils/IndexUrlTestWithConstant.php [new file with mode: 0644]
tests/http/HttpUtils/IsHttpsTest.php
tests/http/HttpUtils/PageUrlTest.php
tests/http/HttpUtils/ServerUrlTest.php
tests/http/UrlTest.php
tests/http/UrlUtils/CleanupUrlTest.php
tests/http/UrlUtils/GetUrlSchemeTest.php
tests/http/UrlUtils/UnparseUrlTest.php
tests/http/UrlUtils/WhitelistProtocolsTest.php
tests/languages/fr/LanguagesFrTest.php
tests/legacy/LegacyControllerTest.php
tests/legacy/LegacyLinkDBTest.php
tests/legacy/LegacyLinkFilterTest.php
tests/legacy/LegacyRouterTest.php [deleted file]
tests/legacy/LegacyUpdaterTest.php
tests/netscape/BookmarkExportTest.php
tests/netscape/BookmarkImportTest.php
tests/plugins/PluginAddlinkTest.php
tests/plugins/PluginArchiveorgTest.php
tests/plugins/PluginDefaultColorsTest.php
tests/plugins/PluginIssoTest.php
tests/plugins/PluginPlayvideosTest.php
tests/plugins/PluginPubsubhubbubTest.php
tests/plugins/PluginQrcodeTest.php
tests/plugins/PluginWallabagTest.php
tests/plugins/WallabagInstanceTest.php
tests/plugins/test/test.php
tests/render/PageCacheManagerTest.php
tests/render/ThemeUtilsTest.php
tests/security/BanManagerTest.php
tests/security/LoginManagerTest.php
tests/security/SessionManagerTest.php
tests/updater/DummyUpdater.php
tests/updater/UpdaterTest.php
tpl/default/includes.html
tpl/default/linklist.html
tpl/default/tag.cloud.html
tpl/default/tag.list.html
tpl/default/tag.sort.html
tpl/vintage/editlink.html
tpl/vintage/linklist.paging.html
webpack.config.js
yarn.lock

diff --git a/.dev/.sasslintrc b/.dev/.sasslintrc
deleted file mode 100644 (file)
index 47c3145..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-options:
-  max-warnings: 0
-rules:
-  property-sort-order:
-    - 0
-# Sort order rule does not work with CSS variables: https://github.com/sasstools/sass-lint/issues/1161
-#    - 1
-#    -
-#      order: 'concentric'
-  no-important:
-    - 0
-  no-vendor-prefixes:
-    - 0 # this will be fixed with v2: see https://github.com/sasstools/sass-lint/pull/1137
-  nesting-depth:
-    - 1
-    -
-      max-depth: 4
diff --git a/.dev/.stylelintrc.js b/.dev/.stylelintrc.js
new file mode 100644 (file)
index 0000000..a754e33
--- /dev/null
@@ -0,0 +1,15 @@
+module.exports = {
+  extends: 'stylelint-config-standard',
+  plugins: [
+    "stylelint-scss"
+  ],
+  rules: {
+    "indentation": [2],
+    "number-leading-zero": null,
+    // Replace CSS @ with SASS ones
+    "at-rule-no-unknown": null,
+    "scss/at-rule-no-unknown": true,
+    // not compatible with SASS apparently
+    "no-descending-specificity": null
+  },
+}
index 366946e8c791e281a5be66258436545dfa2d712f..15a25e43cbb562f1f96fb2b6a39e6d234678c39d 100644 (file)
@@ -3,6 +3,7 @@ ArthurHoaro <arthur@hoa.ro> Arthur
 Florian Eula <eula.florian@gmail.com> feula
 Florian Eula <eula.florian@gmail.com> <mr.pikzen@gmail.com>
 Immánuel Fodor <immanuelfactor+github@gmail.com>
+Immánuel Fodor <immanuelfactor+github@gmail.com> Immánuel! <21174107+immanuelfodor@users.noreply.github.com>
 kalvn <kalvnthereal@gmail.com> <kalvn@users.noreply.github.com>
 kalvn <kalvnthereal@gmail.com> <kalvn@pm.me>
 Neros <contact@neros.fr> <NerosTie@users.noreply.github.com>
index 4c00427195ecb0998589fc09dd02fa8580d97a3e..25fcfb034ee3e1bf1149eafdfccc5b9d27803fe2 100644 (file)
--- a/.htaccess
+++ b/.htaccess
@@ -7,31 +7,20 @@ RewriteEngine On
 RewriteRule ^(.git|doxygen|vendor) - [F]
 
 # Forward the "Authorization" HTTP header
+# fixes JWT token not correctly forwarded on some Apache/FastCGI setups
 RewriteCond %{HTTP:Authorization} ^(.*)
 RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
+# Alternative (if the 2 lines above don't work)
+# SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
 
 # REST API
+# Ionos Hosting needs RewriteBase /
+# RewriteBase /
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteRule ^ index.php [QSA,L]
 
-<Limit GET POST PUT DELETE OPTIONS>
-  <IfModule version_module>
-    <IfVersion >= 2.4>
-       Require all granted
-    </IfVersion>
-    <IfVersion < 2.4>
-       Allow from all
-       Deny from none
-    </IfVersion>
-  </IfModule>
-
-  <IfModule !version_module>
-    Require all granted
-  </IfModule>
-</Limit>
-
-<LimitExcept GET POST PUT DELETE OPTIONS>
+<LimitExcept GET POST PUT DELETE PATCH OPTIONS>
   <IfModule version_module>
     <IfVersion >= 2.4>
        Require all denied
index d04a45d14e2d92d2004762658dd0315c43eae29c..d7460947383a0e595f472908da81ffcec78ef040 100644 (file)
@@ -2,6 +2,15 @@ dist: bionic
 
 matrix:
   include:
+    # jobs for each supported php version
+    - language: php
+      php: nightly # PHP 8.0
+      install:
+        - composer self-update --2
+        - composer update --ignore-platform-req=php
+        - composer remove --dev --ignore-platform-req=php phpunit/phpunit
+        - composer require --dev --ignore-platform-req=php phpunit/php-text-template ^2.0
+        - composer require --dev --ignore-platform-req=php phpunit/phpunit ^9.0
     - language: php
       php: 7.4
     - language: php
@@ -10,23 +19,22 @@ matrix:
       php: 7.2
     - language: php
       php: 7.1
+    # jobs for frontend builds
     - language: node_js
-      node_js: 8
+      node_js: 10
       cache:
         yarn: true
         directories:
           - $HOME/.cache/yarn
-
       install:
         - yarn install
-
       before_script:
         - PATH=${PATH//:\.\/node_modules\/\.bin/}
-
       script:
-        - yarn run build # Just to be sure that the build isn't broken
-        - make eslint
-        - make sasslint
+        - yarn run build # verify successful frontend builds
+        - make eslint # javascript static analysis
+        - make sasslint # linter for SASS syntax
+    # jobs for documentation builds
     - language: python
       python: 3.6
       cache:
@@ -42,7 +50,9 @@ cache:
     - $HOME/.composer/cache
 
 install:
-  - composer install --prefer-dist
+  # install/update composer and php dependencies
+  - composer config --unset platform && composer config platform.php $TRAVIS_PHP_VERSION
+  - composer update
 
 before_script:
   - PATH=${PATH//:\.\/node_modules\/\.bin/}
diff --git a/AUTHORS b/AUTHORS
index 9c5028ebeb5250387744ada1f546faebd5d0796c..0ec52accb570c55861e047eed49290e420115582 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,23 +1,26 @@
-   903 ArthurHoaro <arthur@hoa.ro>
+   991 ArthurHoaro <arthur@hoa.ro>
    402 VirtualTam <virtualtam@flibidi.net>
-   250 nodiscc <nodiscc@gmail.com>
+   294 nodiscc <nodiscc@gmail.com>
     56 Sébastien Sauvage <sebsauvage@sebsauvage.net>
     16 Luce Carević <lcarevic@access42.net>
     15 Florian Eula <eula.florian@gmail.com>
     13 Emilien Klein <emilien@klein.st>
     12 Nicolas Danelon <hi@nicolasmd.com.ar>
+     9 Lucas Cimon <lucas.cimon@gmail.com>
      9 Willi Eggeling <thewilli@gmail.com>
      8 Christophe HENRY <christophe.henry@sbgodin.fr>
-     7 Lucas Cimon <lucas.cimon@gmail.com>
      6 B. van Berkum <dev@dotmpe.com>
+     6 Immánuel Fodor <immanuelfactor+github@gmail.com>
+     6 Keith Carangelo <mail@kcaran.com>
      6 kalvn <kalvnthereal@gmail.com>
      6 llune <llune@users.noreply.github.com>
      5 Mark Schmitz <kramred@gmail.com>
      5 Sébastien NOBILI <code@pipoprods.org>
+     5 dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
      4 Alexandre Alapetite <alexandre@alapetite.fr>
      4 David Sferruzza <david.sferruzza@gmail.com>
-     4 Immánuel Fodor <immanuelfactor+github@gmail.com>
      3 Agurato <mail.vmonot@gmail.com>
+     3 Christoph Stoettner <christoph.stoettner@stoeps.de>
      3 Teromene <teromene@teromene.fr>
      2 Alexandre G.-Raymond <alex@ndre.gr>
      2 Chris Kuethe <chris.kuethe@gmail.com>
@@ -30,7 +33,6 @@
      2 Qwerty <champlywood@free.fr>
      2 Stephen Muth <smuth4@gmail.com>
      2 Timo Van Neerden <fire@lehollandaisvolant.net>
-     2 dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
      2 flow.gunso <flow.gunso@gmail.com>
      2 julienCXX <software@chmodplusx.eu>
      2 philipp-r <philipp-r@users.noreply.github.com>
@@ -75,4 +77,6 @@
      1 dimtion <zizou.xena@gmail.com>
      1 durcheinandr <jochen@durcheinandr.de>
      1 lapineige <lapineige@users.noreply.github.com>
+     1 owen bell <66233223+xfnw@users.noreply.github.com>
      1 rfolo9li <50079896+rfolo9li@users.noreply.github.com>
+     1 sprak3000 <sprak3000+github@gmail.com>
index 4bae5b487a846243ca282a6f88889bd36829cff8..f1686d67f3564e913b30d483dcaf8eb52cff2b7f 100644 (file)
@@ -4,19 +4,20 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
-## [v0.12.0](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0-beta) - UNRELEASED [beta 2020-08-27]
+## [v0.12.1]() - UNRELEASED
 
-**Save you `data/` folder before updating!**
+## [v0.12.0](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0) - 2020-10-13
 
-This is a beta version containing major changes, including new URLs for Shaarli and datastore format update.
-Be aware that by using a beta version you might encounter bugs, and that 3rd party themes or plugins might not be compatible.
+**Save you `data/` folder before updating!**
 
 ### Added
 - Thumbnailer: add soundcloud.com to list of common media domains
 - Markdown rendering is now integrated into Shaarli core
 - Add autofocus on tag cloud filter input
 - Japanese translations
-- Support for local anchor URL (startting with `#`)
+- Japanese translation: add language to admin configuration page
+- Support for PHP 8.0
+- Support for local anchor URL (starting with `#`)
 - LDAP authentication
 - Encapsulated PageCacheManager
 - Docs:
@@ -24,18 +25,24 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par
   - section about mkdocs
   - Ulauncher extension
 - CI: run against PHP 7.4
+- Added $links_per_page variable to template and display on default
+- Inject BookmarkServiceInterface in plugins data
+- Add manual configuration for root URL
+- Added PATCH to the allowed Apache request methods.
+- REST API: compatibility with ionos Apache's headers
 
 ### Changed
 - Introduce Bookmark object and Service layer
   - Save bookmark as objects in the datastore
   - Handle bookmark as objects across the whole codebase (except templates and plugins)
 - Process all Shaarli page through Slim controller, with proper URL rewriting (see #1516)
+- Docs: the entire documentation has been reviewed, updated and improved, thanks to @nodiscc!
 - ATOM feed: use instance name as author name instead of URL
 - Updated French translation
-- Docs:
-  - Troubleshooting page rewritten
-  - Updated unit tests page
-  - Updated Server security page
+- Default colors plugin: generate CSS file during initialization
+- Improve default bookmarks after install
+- Upgrade all front end dependencies and webpack build
+- Default theme: Make tag cloud/list views buttons more obvious
 
 ### Fixed
 - Undefined index: thumbnail in daily page
@@ -54,15 +61,20 @@ Be aware that by using a beta version you might encounter bugs, and that 3rd par
 - Division by zero in tag cloud
 - CI: deprecated linux distribution and sudo directive
 - Docker build: gcc is no longer included in python alpine image
+- Default template: display pin button in mobile view
+- Pinned bookmarks are not longer displayed first in ATOM/RSS feeds
 - Docs:
   - Outdated Docker documentation for stable branch
   - Outdated links
   - Plugin description in meta files
+- docker-compose.yml: pin traefik image to 1.7-alpine
 
 ### Removed
 - Markdown plugin
 - Docs:
   - emojione & twemoji removed
+- Makefile: remove static_analysis_summary from all: target
+- doc/Makefile: remove references to composer update
 
 ## [v0.11.1](https://github.com/shaarli/Shaarli/releases/tag/v0.11.1) - 2019-08-03
 
index b52ba22f72382b1573d54591ac4e17e6ab848e3f..0ff6bd3f7a5ef59ed7900b29a3b093855352b928 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 
 BIN = vendor/bin
 
-all: static_analysis_summary check_permissions test
+all: check_permissions test
 
 ##
 # Docker test adapter
@@ -85,6 +85,10 @@ all_tests: test locale_test_de_DE locale_test_en_US locale_test_fr_FR
        @# --text doesn't work with phpunit 4.* (v5 requires PHP 5.6)
        @#$(BIN)/phpcov merge --text coverage/txt coverage
 
+### download 3rd-party PHP libraries, including dev dependencies
+composer_dependencies_dev: clean
+       composer install --prefer-dist
+
 ##
 # Custom release archive generation
 #
@@ -174,4 +178,4 @@ eslint:
 
 ### Run CSSLint check against Shaarli's SCSS files
 sasslint:
-       @yarn run sass-lint -c .dev/.sasslintrc 'assets/default/scss/*.scss' -v -q
+       @yarn run stylelint --config .dev/.stylelintrc.js 'assets/default/scss/*.scss'
index 4fb0bfe0d07748ce7c4b39bf5de0e84b95c70374..46dda8d5e3e0fb874419a0f617e65f36826d1229 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,13 +6,13 @@ _Do you want to share the links you discover?_
 _Shaarli is a minimalist link sharing service that you can install on your own server._
 _It is designed to be personal (single-user), fast and handy._
 
-[![](https://img.shields.io/badge/stable-v0.10.4-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4)
+[![](https://img.shields.io/badge/stable-v0.11.1-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.11.1)
 [![](https://img.shields.io/travis/shaarli/Shaarli/stable.svg?label=stable)](https://travis-ci.org/shaarli/Shaarli)
 &bull;
-[![](https://img.shields.io/badge/latest-v0.11.1-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.11.1)
+[![](https://img.shields.io/badge/latest-v0.12.0-blue.svg)](https://github.com/shaarli/Shaarli/releases/tag/v0.12.0)
 [![](https://img.shields.io/travis/shaarli/Shaarli/latest.svg?label=latest)](https://travis-ci.org/shaarli/Shaarli)
 &bull;
-[![](https://img.shields.io/badge/master-v0.11.x-blue.svg)](https://github.com/shaarli/Shaarli)
+[![](https://img.shields.io/badge/master-v0.12.x-blue.svg)](https://github.com/shaarli/Shaarli)
 [![](https://img.shields.io/travis/shaarli/Shaarli.svg?label=master)](https://travis-ci.org/shaarli/Shaarli)
 
 [![Join the chat at https://gitter.im/shaarli/Shaarli](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shaarli/Shaarli)
index 9c9eaaa2611eff24d62d24eb2d30e2da372d4aad..bcfda65c9ca14cef75aac304396f0512dba500d5 100644 (file)
@@ -95,14 +95,14 @@ function escape($input)
         return null;
     }
 
-    if (is_bool($input)) {
+    if (is_bool($input) || is_int($input) || is_float($input) || $input instanceof DateTimeInterface) {
         return $input;
     }
 
     if (is_array($input)) {
         $out = array();
         foreach ($input as $key => $value) {
-            $out[$key] = escape($value);
+            $out[escape($key)] = escape($value);
         }
         return $out;
     }
index 09ce6445303bf5f9280e033c6004bf5e56f725c9..f5b53b01fcc5f5f16c5d477d054c9483d2e142d9 100644 (file)
@@ -107,7 +107,9 @@ class ApiMiddleware
      */
     protected function checkToken($request)
     {
-        if (! $request->hasHeader('Authorization')) {
+        if (!$request->hasHeader('Authorization')
+            && !isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])
+        ) {
             throw new ApiAuthorizationException('JWT token not provided');
         }
 
@@ -115,7 +117,11 @@ class ApiMiddleware
             throw new ApiAuthorizationException('Token secret must be set in Shaarli\'s administration');
         }
 
-        $authorization = $request->getHeaderLine('Authorization');
+        if (isset($this->container->environment['REDIRECT_HTTP_AUTHORIZATION'])) {
+            $authorization = $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'];
+        } else {
+            $authorization = $request->getHeaderLine('Authorization');
+        }
 
         if (! preg_match('/^Bearer (.*)/i', $authorization, $matches)) {
             throw new ApiAuthorizationException('Invalid JWT header');
index faebb8f5f00685f4a2413d429a3a917c2adc2833..4a6326f0f7dccc38651f6b8daf979b896cbc1c36 100644 (file)
@@ -94,7 +94,7 @@ class ApiUtils
      *
      * @return Bookmark instance.
      */
-    public static function buildLinkFromRequest($input, $defaultPrivate)
+    public static function buildBookmarkFromRequest($input, $defaultPrivate): Bookmark
     {
         $bookmark = new Bookmark();
         $url = ! empty($input['url']) ? cleanup_url($input['url']) : '';
@@ -110,6 +110,15 @@ class ApiUtils
         $bookmark->setTags(! empty($input['tags']) ? $input['tags'] : []);
         $bookmark->setPrivate($private);
 
+        $created = \DateTime::createFromFormat(\DateTime::ATOM, $input['created'] ?? '');
+        if ($created instanceof \DateTimeInterface) {
+            $bookmark->setCreated($created);
+        }
+        $updated = \DateTime::createFromFormat(\DateTime::ATOM, $input['updated'] ?? '');
+        if ($updated instanceof \DateTimeInterface) {
+            $bookmark->setUpdated($updated);
+        }
+
         return $bookmark;
     }
 
index c4b3d0c3df983484c535d5396530c93843688cdd..88a845ebc0b8557be699a5292b4a55c91911dc6a 100644 (file)
@@ -4,6 +4,7 @@ namespace Shaarli\Api\Controllers;
 
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
+use Shaarli\History;
 use Slim\Container;
 
 /**
@@ -31,7 +32,7 @@ abstract class ApiController
     protected $bookmarkService;
 
     /**
-     * @var HistoryController
+     * @var History
      */
     protected $history;
 
index 2924795012d4c1cd037a008ecfd9f6fdb091ad49..778097fdf9ac73e3f0f367afd18186ee6e705505 100644 (file)
@@ -116,7 +116,7 @@ class Links extends ApiController
     public function postLink($request, $response)
     {
         $data = $request->getParsedBody();
-        $bookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links'));
+        $bookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
         // duplicate by URL, return 409 Conflict
         if (! empty($bookmark->getUrl())
             && ! empty($dup = $this->bookmarkService->findByUrl($bookmark->getUrl()))
@@ -155,7 +155,7 @@ class Links extends ApiController
         $index = index_url($this->ci['environment']);
         $data = $request->getParsedBody();
 
-        $requestBookmark = ApiUtils::buildLinkFromRequest($data, $this->conf->get('privacy.default_private_links'));
+        $requestBookmark = ApiUtils::buildBookmarkFromRequest($data, $this->conf->get('privacy.default_private_links'));
         // duplicate URL on a different link, return 409 Conflict
         if (! empty($requestBookmark->getUrl())
             && ! empty($dup = $this->bookmarkService->findByUrl($requestBookmark->getUrl()))
index e3a611461a7aae9ecd3f0070a3341aa872aa737d..c9ec260930d159f8603f1f5c796fbec5612c08c2 100644 (file)
@@ -362,7 +362,9 @@ class BookmarkFileService implements BookmarkServiceInterface
      */
     public function filterDay($request)
     {
-        return $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_DAY, $request);
+        $visibility = $this->isLoggedIn ? BookmarkFilter::$ALL : BookmarkFilter::$PUBLIC;
+
+        return $this->bookmarkFilter->filter(BookmarkFilter::$FILTER_DAY, $request, false, $visibility);
     }
 
     /**
index 797a36b8ecd54c34a7aaea1ac63d3db0c2496bc8..6636bbfeec63e6e759154eda8bde4c377337d26c 100644 (file)
@@ -115,7 +115,7 @@ class BookmarkFilter
                     return $this->filterTags($request, $casesensitive, $visibility);
                 }
             case self::$FILTER_DAY:
-                return $this->filterDay($request);
+                return $this->filterDay($request, $visibility);
             default:
                 return $this->noFilter($visibility);
         }
@@ -425,21 +425,26 @@ class BookmarkFilter
      *  print_r($mydb->filterDay('20120125'));
      *
      * @param string $day day to filter.
-     *
+     * @param string $visibility return only all/private/public bookmarks.
+
      * @return array all link matching given day.
      *
      * @throws Exception if date format is invalid.
      */
-    public function filterDay($day)
+    public function filterDay($day, $visibility)
     {
         if (!checkDateFormat('Ymd', $day)) {
             throw new Exception('Invalid date format');
         }
 
         $filtered = [];
-        foreach ($this->bookmarks as $key => $l) {
-            if ($l->getCreated()->format('Ymd') == $day) {
-                $filtered[$key] = $l;
+        foreach ($this->bookmarks as $key => $bookmark) {
+            if ($visibility === static::$PUBLIC && $bookmark->isPrivate()) {
+                continue;
+            }
+
+            if ($bookmark->getCreated()->format('Ymd') == $day) {
+                $filtered[$key] = $bookmark;
             }
         }
 
index cd2d1724c1ad088193ffe51c1bde44a7d4ab2c2b..815047e38010d5123cb5f27539e7d5ec55fb419d 100644 (file)
@@ -34,25 +34,77 @@ class BookmarkInitializer
     public function initialize()
     {
         $bookmark = new Bookmark();
-        $bookmark->setTitle(t('My secret stuff... - Pastebin.com'));
-        $bookmark->setUrl('http://sebsauvage.net/paste/?8434b27936c09649#bR7XsXhoTiLcqCpQbmOpBi3rq2zzQUC5hBI7ZT1O3x8=');
-        $bookmark->setDescription(t('Shhhh! I\'m a private link only YOU can see. You can delete me too.'));
-        $bookmark->setTagsString('secretstuff');
+        $bookmark->setTitle('quicksilver (loop) on Vimeo ' . t('(private bookmark with thumbnail demo)'));
+        $bookmark->setUrl('https://vimeo.com/153493904');
+        $bookmark->setDescription(t(
+'Shaarli will automatically pick up the thumbnail for links to a variety of websites.
+
+Explore your new Shaarli instance by trying out controls and menus.
+Visit the project on [Github](https://github.com/shaarli/Shaarli) or [the documentation](https://shaarli.readthedocs.io/en/master/) to learn more about Shaarli.
+
+Now you can edit or delete the default shaares.
+'
+        ));
+        $bookmark->setTagsString('shaarli help thumbnail');
+        $bookmark->setPrivate(true);
+        $this->bookmarkService->add($bookmark, false);
+
+        $bookmark = new Bookmark();
+        $bookmark->setTitle(t('Note: Shaare descriptions'));
+        $bookmark->setDescription(t(
+'Adding a shaare without entering a URL creates a text-only "note" post such as this one.
+This note is private, so you are the only one able to see it while logged in.
+
+You can use this to keep notes, post articles, code snippets, and much more.
+
+The Markdown formatting setting allows you to format your notes and bookmark description:
+
+### Title headings
+
+#### Multiple headings levels
+  * bullet lists
+  * _italic_ text
+  * **bold** text
+  * ~~strike through~~ text
+  * `code` blocks
+  * images
+  * [links](https://en.wikipedia.org/wiki/Markdown)
+
+Markdown also supports tables:
+
+| Name    | Type      | Color  | Qty   |
+| ------- | --------- | ------ | ----- |
+| Orange  | Fruit     | Orange | 126   |
+| Apple   | Fruit     | Any    | 62    |
+| Lemon   | Fruit     | Yellow | 30    |
+| Carrot  | Vegetable | Red    | 14    |
+'
+        ));
+        $bookmark->setTagsString('shaarli help');
         $bookmark->setPrivate(true);
         $this->bookmarkService->add($bookmark, false);
 
         $bookmark = new Bookmark();
-        $bookmark->setTitle(t('The personal, minimalist, super-fast, database free, bookmarking service'));
-        $bookmark->setUrl('https://shaarli.readthedocs.io', []);
+        $bookmark->setTitle(
+            'Shaarli - ' . t('The personal, minimalist, super-fast, database free, bookmarking service')
+        );
         $bookmark->setDescription(t(
-            'Welcome to Shaarli! This is your first public bookmark. '
-            . 'To edit or delete me, you must first login.
+'Welcome to Shaarli!
+
+Shaarli allows you to bookmark your favorite pages, and share them with others or store them privately.
+You can add a description to your bookmarks, such as this one, and tag them.
+
+Create a new shaare by clicking the `+Shaare` button, or using any of the recommended tools (browser extension, mobile app, bookmarklet, REST API, etc.).
 
-To learn how to use Shaarli, consult the link "Documentation" at the bottom of this page.
+You can easily retrieve your links, even with thousands of them, using the internal search engine, or search through tags (e.g. this Shaare is tagged with `shaarli` and `help`).
+Hashtags such as #shaarli #help are also supported.
+You can also filter the available [RSS feed](/feed/atom) and picture wall by tag or plaintext search.
 
-You use the community supported version of the original Shaarli project, by Sebastien Sauvage.'
+We hope that you will enjoy using Shaarli, maintained with ❤️ by the community!
+Feel free to open [an issue](https://github.com/shaarli/Shaarli/issues) if you have a suggestion or encounter an issue.
+'
         ));
-        $bookmark->setTagsString('opensource software');
+        $bookmark->setTagsString('shaarli help');
         $this->bookmarkService->add($bookmark, false);
     }
 }
index 03e1b82a7ec4d69d55c066a810c6a8fd15bab2e7..faf5dbfd4fe24906bf980d8f4cc72e0472b7e008 100644 (file)
@@ -26,7 +26,7 @@ function html_extract_title($html)
  */
 function header_extract_charset($header)
 {
-    preg_match('/charset="?([^; ]+)/i', $header, $match);
+    preg_match('/charset=["\']?([^; "\']+)/i', $header, $match);
     if (! empty($match[1])) {
         return strtolower(trim($match[1]));
     }
index 4509357ce887ea8a28334a68c50f999294780243..c0c0dab9ab9df4ce10f0a8217ae28a88dc011483 100644 (file)
@@ -46,7 +46,7 @@ class ConfigJson implements ConfigIO
         // JSON_PRETTY_PRINT is available from PHP 5.4.
         $print = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
         $data = self::getPhpHeaders() . json_encode($conf, $print) . self::getPhpSuffix();
-        if (!file_put_contents($filepath, $data)) {
+        if (empty($filepath) || !file_put_contents($filepath, $data)) {
             throw new \Shaarli\Exceptions\IOException(
                 $filepath,
                 t('Shaarli could not create the config file. '.
index 58067c9945319d7d7bb664d37c0589fe71b8d377..55bb51b5b46506f95b2d79280796c694cc1e9fc9 100644 (file)
@@ -10,6 +10,7 @@ use Shaarli\Config\ConfigManager;
 use Shaarli\Feed\FeedBuilder;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\Front\Controller\Visitor\ErrorController;
+use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
 use Shaarli\History;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
@@ -149,6 +150,9 @@ class ContainerBuilder
             );
         };
 
+        $container['notFoundHandler'] = function (ShaarliContainer $container): ErrorNotFoundController {
+            return new ErrorNotFoundController($container);
+        };
         $container['errorHandler'] = function (ShaarliContainer $container): ErrorController {
             return new ErrorController($container);
         };
index 9a9a974a6785bce8077e818607dc75e5dbee7e63..66e669aaed3fd6760c966d0fbfd1689696c74f20 100644 (file)
@@ -24,21 +24,22 @@ use Slim\Container;
 /**
  * Extension of Slim container to document the injected objects.
  *
- * @property string                   $basePath             Shaarli's instance base path (e.g. `/shaarli/`)
+ * @property string                   $basePath              Shaarli's instance base path (e.g. `/shaarli/`)
  * @property BookmarkServiceInterface $bookmarkService
  * @property CookieManager            $cookieManager
  * @property ConfigManager            $conf
- * @property mixed[]                  $environment          $_SERVER automatically injected by Slim
- * @property callable                 $errorHandler         Overrides default Slim exception display
+ * @property mixed[]                  $environment           $_SERVER automatically injected by Slim
+ * @property callable                 $errorHandler          Overrides default Slim exception display
  * @property FeedBuilder              $feedBuilder
  * @property FormatterFactory         $formatterFactory
  * @property History                  $history
  * @property HttpAccess               $httpAccess
  * @property LoginManager             $loginManager
  * @property NetscapeBookmarkUtils    $netscapeBookmarkUtils
+ * @property callable                 $notFoundHandler       Overrides default Slim exception display
  * @property PageBuilder              $pageBuilder
  * @property PageCacheManager         $pageCacheManager
- * @property callable                 $phpErrorHandler      Overrides default Slim PHP error display
+ * @property callable                 $phpErrorHandler       Overrides default Slim PHP error display
  * @property PluginManager            $pluginManager
  * @property SessionManager           $sessionManager
  * @property Thumbnailer              $thumbnailer
index 3653c32f981b360d52d556e4ea48e5ee6c1e4ab3..f6def6308849eb6401fd908a4d063046f163dc11 100644 (file)
@@ -122,9 +122,9 @@ class FeedBuilder
         $data['language'] = $this->getTypeLanguage($feedType);
         $data['last_update'] = $this->getLatestDateFormatted($feedType);
         $data['show_dates'] = !$this->hideDates || $this->isLoggedIn;
-        // Remove leading slash from REQUEST_URI.
-        $data['self_link'] = escape(server_url($this->serverInfo))
-            . escape($this->serverInfo['REQUEST_URI']);
+        // Remove leading path from REQUEST_URI (already contained in $pageaddr).
+        $requestUri = preg_replace('#(.*?/)(feed.*)#', '$2', escape($this->serverInfo['REQUEST_URI']));
+        $data['self_link'] = $pageaddr . $requestUri;
         $data['index_url'] = $pageaddr;
         $data['usepermalinks'] = $this->usePermalinks === true;
         $data['links'] = $linkDisplayed;
index 22ba7aae78173338d501fd56e462e2891458d081..0042dafe402958905b892cdb2617e767dfdb8d11 100644 (file)
@@ -58,7 +58,9 @@ abstract class BookmarkFormatter
         $out['title'] = $this->formatTitle($bookmark);
         $out['description'] = $this->formatDescription($bookmark);
         $out['thumbnail'] = $this->formatThumbnail($bookmark);
+        $out['urlencoded_taglist'] = $this->formatUrlEncodedTagList($bookmark);
         $out['taglist'] = $this->formatTagList($bookmark);
+        $out['urlencoded_tags'] = $this->formatUrlEncodedTagString($bookmark);
         $out['tags'] = $this->formatTagString($bookmark);
         $out['sticky'] = $bookmark->isSticky();
         $out['private'] = $bookmark->isPrivate();
@@ -181,6 +183,18 @@ abstract class BookmarkFormatter
         return $this->filterTagList($bookmark->getTags());
     }
 
+    /**
+     * Format Url Encoded Tags
+     *
+     * @param Bookmark $bookmark instance
+     *
+     * @return array formatted Tags
+     */
+    protected function formatUrlEncodedTagList($bookmark)
+    {
+        return array_map('urlencode', $this->filterTagList($bookmark->getTags()));
+    }
+
     /**
      * Format TagString
      *
@@ -193,6 +207,18 @@ abstract class BookmarkFormatter
         return implode(' ', $this->formatTagList($bookmark));
     }
 
+    /**
+     * Format TagString
+     *
+     * @param Bookmark $bookmark instance
+     *
+     * @return string formatted TagString
+     */
+    protected function formatUrlEncodedTagString($bookmark)
+    {
+        return implode(' ', $this->formatUrlEncodedTagList($bookmark));
+    }
+
     /**
      * Format Class
      * Used to add specific CSS class for a link
diff --git a/application/formatter/BookmarkMarkdownExtraFormatter.php b/application/formatter/BookmarkMarkdownExtraFormatter.php
new file mode 100644 (file)
index 0000000..0694b23
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+namespace Shaarli\Formatter;
+
+use Shaarli\Config\ConfigManager;
+
+/**
+ * Class BookmarkMarkdownExtraFormatter
+ *
+ * Format bookmark description into MarkdownExtra format.
+ *
+ * @see https://michelf.ca/projects/php-markdown/extra/
+ *
+ * @package Shaarli\Formatter
+ */
+class BookmarkMarkdownExtraFormatter extends BookmarkMarkdownFormatter
+{
+    public function __construct(ConfigManager $conf, bool $isLoggedIn)
+    {
+        parent::__construct($conf, $isLoggedIn);
+
+        $this->parsedown = new \ParsedownExtra();
+    }
+}
index e675fccabad0eacf408acc0901c113d0e777a5c9..0ed7ad81086d93b6a0c0d39e3a539dd398a8fb62 100644 (file)
@@ -30,7 +30,7 @@ class ConfigureController extends ShaarliAdminController
             'theme_available',
             ThemeUtils::getThemes($this->container->conf->get('resource.raintpl_tpl'))
         );
-        $this->assignView('formatter_available', ['default', 'markdown']);
+        $this->assignView('formatter_available', ['default', 'markdown', 'markdownExtra']);
         list($continents, $cities) = generateTimeZoneData(
             timezone_identifiers_list(),
             $this->container->conf->get('general.timezone')
index 33e1188ef73a6f0df55c2daba25e88cea29d8f91..bb083486591055b5eddd7c3a75610b69d869eb33 100644 (file)
@@ -69,7 +69,7 @@ class ManageShaareController extends ShaarliAdminController
                         $retrieveDescription
                     )
                 );
-                if (! empty($title) && strtolower($charset) !== 'utf-8') {
+                if (! empty($title) && strtolower($charset) !== 'utf-8' && mb_check_encoding($charset)) {
                     $title = mb_convert_encoding($title, 'utf-8', $charset);
                 }
             }
@@ -78,13 +78,13 @@ class ManageShaareController extends ShaarliAdminController
                 $title = $this->container->conf->get('general.default_note_title', t('Note: '));
             }
 
-            $link = escape([
+            $link = [
                 'title' => $title,
                 'url' => $url ?? '',
                 'description' => $description ?? '',
                 'tags' => $tags ?? '',
                 'private' => $private,
-            ]);
+            ];
         } else {
             $formatter = $this->container->formatterFactory->getFormatter('raw');
             $link = $formatter->format($bookmark);
@@ -127,7 +127,7 @@ class ManageShaareController extends ShaarliAdminController
         $this->checkToken($request);
 
         // lf_id should only be present if the link exists.
-        $id = $request->getParam('lf_id') ? intval(escape($request->getParam('lf_id'))) : null;
+        $id = $request->getParam('lf_id') !== null ? intval(escape($request->getParam('lf_id'))) : null;
         if (null !== $id && true === $this->container->bookmarkService->exists($id)) {
             // Edit
             $bookmark = $this->container->bookmarkService->get($id);
@@ -169,7 +169,7 @@ class ManageShaareController extends ShaarliAdminController
         return $this->redirectFromReferer(
             $request,
             $response,
-            ['add-shaare', 'shaare'], ['addlink', 'post', 'edit_link'],
+            ['/admin/add-shaare', '/admin/shaare'], ['addlink', 'post', 'edit_link'],
             $bookmark->getShortUrl()
         );
     }
@@ -345,14 +345,14 @@ class ManageShaareController extends ShaarliAdminController
             $tags[BookmarkMarkdownFormatter::NO_MD_TAG] = 1;
         }
 
-        $data = [
+        $data = escape([
             'link' => $link,
             'link_is_new' => $isNew,
-            'http_referer' => escape($this->container->environment['HTTP_REFERER'] ?? ''),
+            'http_referer' => $this->container->environment['HTTP_REFERER'] ?? '',
             'source' => $request->getParam('source') ?? '',
             'tags' => $tags,
             'default_private_links' => $this->container->conf->get('privacy.default_private_links', false),
-        ];
+        ]);
 
         $this->executePageHooks('render_editlink', $data, TemplatePage::EDIT_LINK);
 
index 0380ef1f2c4166cd818e52b72d6be36279bfdecd..2065c3e27cbdac21c43d68901c197aee05253805 100644 (file)
@@ -41,8 +41,8 @@ class ManageTagController extends ShaarliAdminController
 
         $isDelete = null !== $request->getParam('deletetag') && null === $request->getParam('renametag');
 
-        $fromTag = escape(trim($request->getParam('fromtag') ?? ''));
-        $toTag = escape(trim($request->getParam('totag') ?? ''));
+        $fromTag = trim($request->getParam('fromtag') ?? '');
+        $toTag = trim($request->getParam('totag') ?? '');
 
         if (0 === strlen($fromTag) || false === $isDelete && 0 === strlen($toTag)) {
             $this->saveWarningMessage(t('Invalid tags provided.'));
index 0e09116e98ddb4ca334455c1db2d69d3b5d3eb69..8e05968199df9e099b61d16c7a3c9494a6e3a672 100644 (file)
@@ -62,6 +62,7 @@ class PluginsController extends ShaarliAdminController
 
             if (isset($parameters['parameters_form'])) {
                 unset($parameters['parameters_form']);
+                unset($parameters['token']);
                 foreach ($parameters as $param => $value) {
                     $this->container->conf->set('plugins.'. $param, escape($value));
                 }
index 3b5939bb6e73df4a7e9ab2083e966f06a3fdd3aa..c26c9cbe2e5050f42fa3da07f72e3d59d63939c0 100644 (file)
@@ -4,9 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use Shaarli\Container\ShaarliContainer;
 use Shaarli\Front\Controller\Visitor\ShaarliVisitorController;
-use Shaarli\Front\Exception\UnauthorizedException;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
 use Slim\Http\Request;
index 2988bee62d089b53296639e576daedc80ca79a4d..18368751be156b13b09b72a2b48aac0fddf484ec 100644 (file)
@@ -34,7 +34,7 @@ class BookmarkListController extends ShaarliVisitorController
         $formatter = $this->container->formatterFactory->getFormatter();
         $formatter->addContextData('base_path', $this->container->basePath);
 
-        $searchTags = escape(normalize_spaces($request->getParam('searchtags') ?? ''));
+        $searchTags = normalize_spaces($request->getParam('searchtags') ?? '');
         $searchTerm = escape(normalize_spaces($request->getParam('searchterm') ?? ''));;
 
         // Filter bookmarks according search parameters.
@@ -104,8 +104,9 @@ class BookmarkListController extends ShaarliVisitorController
                 'page_current' => $page,
                 'page_max' => $pageCount,
                 'result_count' => count($linksToDisplay),
-                'search_term' => $searchTerm,
-                'search_tags' => $searchTags,
+                'search_term' => escape($searchTerm),
+                'search_tags' => escape($searchTags),
+                'search_tags_url' => array_map('urlencode', explode(' ', $searchTags)),
                 'visibility' => $visibility,
                 'links' => $linkDisp,
             ]
index 54a4778fa3280d7b75829ed01a41bd42253cba89..07617cf11fdfe49b047c24d0641477ad6b66e8d4 100644 (file)
@@ -132,7 +132,7 @@ class DailyController extends ShaarliVisitorController
                 'date' => $dayDatetime,
                 'date_rss' => $dayDatetime->format(DateTime::RSS),
                 'date_human' => format_date($dayDatetime, false, true),
-                'absolute_url' => $indexUrl . '/daily?day=' . $day,
+                'absolute_url' => $indexUrl . 'daily?day=' . $day,
                 'links' => [],
             ];
 
diff --git a/application/front/controller/visitor/ErrorNotFoundController.php b/application/front/controller/visitor/ErrorNotFoundController.php
new file mode 100644 (file)
index 0000000..758dd83
--- /dev/null
@@ -0,0 +1,29 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller\Visitor;
+
+use Slim\Http\Request;
+use Slim\Http\Response;
+
+/**
+ * Controller used to render the 404 error page.
+ */
+class ErrorNotFoundController extends ShaarliVisitorController
+{
+    public function __invoke(Request $request, Response $response): Response
+    {
+        // Request from the API
+        if (false !== strpos($request->getRequestTarget(), '/api/v1')) {
+            return $response->withStatus(404);
+        }
+
+        // This is required because the middleware is ignored if the route is not found.
+        $this->container->basePath = rtrim($request->getUri()->getBasePath(), '/');
+
+        $this->assignView('error_message', t('Requested page could not be found.'));
+
+        return $response->withStatus(404)->write($this->render('404'));
+    }
+}
index da2848c2b0151b115d5d3427236a7f039c96265b..8d8b546aad35cc58573e0083b3ed9d283c0b71a7 100644 (file)
@@ -46,10 +46,10 @@ class FeedController extends ShaarliVisitorController
 
         $data = $this->container->feedBuilder->buildData($feedType, $request->getParams());
 
-        $this->executePageHooks('render_feed', $data, $feedType);
+        $this->executePageHooks('render_feed', $data, 'feed.' . $feedType);
         $this->assignAllView($data);
 
-        $content = $this->render('feed.'. $feedType);
+        $content = $this->render('feed.' . $feedType);
 
         $cache->cache($content);
 
index f17c8ed37936550304cfdfbe59735e98e677c4e4..55c075a2a87f7ae8c7cad95c5134bf78c53e3cf5 100644 (file)
@@ -78,16 +78,14 @@ abstract class ShaarliVisitorController
             'footer',
         ];
 
+        $parameters = $this->buildPluginParameters($template);
+
         foreach ($common_hooks as $name) {
             $pluginData = [];
             $this->container->pluginManager->executeHooks(
                 'render_' . $name,
                 $pluginData,
-                [
-                    'target' => $template,
-                    'loggedin' => $this->container->loginManager->isLoggedIn(),
-                    'basePath' => $this->container->basePath,
-                ]
+                $parameters
             );
             $this->assignView('plugins_' . $name, $pluginData);
         }
@@ -95,19 +93,23 @@ abstract class ShaarliVisitorController
 
     protected function executePageHooks(string $hook, array &$data, string $template = null): void
     {
-        $params = [
-            'target' => $template,
-            'loggedin' => $this->container->loginManager->isLoggedIn(),
-            'basePath' => $this->container->basePath,
-        ];
-
         $this->container->pluginManager->executeHooks(
             $hook,
             $data,
-            $params
+            $this->buildPluginParameters($template)
         );
     }
 
+    protected function buildPluginParameters(?string $template): array
+    {
+        return [
+            'target' => $template,
+            'loggedin' => $this->container->loginManager->isLoggedIn(),
+            'basePath' => $this->container->basePath,
+            'bookmarkService' => $this->container->bookmarkService
+        ];
+    }
+
     /**
      * Simple helper which prepend the base path to redirect path.
      *
@@ -140,6 +142,13 @@ abstract class ShaarliVisitorController
 
         if (null !== $referer) {
             $currentUrl = parse_url($referer);
+            // If the referer is not related to Shaarli instance, redirect to default
+            if (isset($currentUrl['host'])
+                && strpos(index_url($this->container->environment), $currentUrl['host']) === false
+            ) {
+                return $response->withRedirect($defaultPath);
+            }
+
             parse_str($currentUrl['query'] ?? '', $params);
             $path = $currentUrl['path'] ?? $defaultPath;
         } else {
index f9c529bcc4fbeab904227c02a4a6f9d673c24898..76ed76900da0f1c75afa1b2dd942cd98a6f6ecda 100644 (file)
@@ -66,10 +66,18 @@ class TagCloudController extends ShaarliVisitorController
             $tags = $this->formatTagsForCloud($tags);
         }
 
+        $tagsUrl = [];
+        foreach ($tags as $tag => $value) {
+            $tagsUrl[escape($tag)] = urlencode((string) $tag);
+        }
+
         $searchTags = implode(' ', escape($filteringTags));
+        $searchTagsUrl = urlencode(implode(' ', $filteringTags));
         $data = [
-            'search_tags' => $searchTags,
-            'tags' => $tags,
+            'search_tags' => escape($searchTags),
+            'search_tags_url' => $searchTagsUrl,
+            'tags' => escape($tags),
+            'tags_url' => $tagsUrl,
         ];
         $this->executePageHooks('render_tag' . $type, $data, 'tag.' . $type);
         $this->assignAllView($data);
index 4fc4e3dcff08f3457c7a2d541962c699979732c7..9f4140735a695c4ab8e08b2c10a8e49eaa3527bb 100644 (file)
@@ -369,7 +369,11 @@ function server_url($server)
  */
 function index_url($server)
 {
-    $scriptname = $server['SCRIPT_NAME'] ?? '';
+    if (defined('SHAARLI_ROOT_URL') && null !== SHAARLI_ROOT_URL) {
+        return rtrim(SHAARLI_ROOT_URL, '/') . '/';
+    }
+
+    $scriptname = !empty($server['SCRIPT_NAME']) ? $server['SCRIPT_NAME'] : '/';
     if (endsWith($scriptname, 'index.php')) {
         $scriptname = substr($scriptname, 0, -9);
     }
@@ -392,7 +396,7 @@ function page_url($server)
         $scriptname = substr($scriptname, 0, -9);
     }
 
-    $route = ltrim($server['REQUEST_URI'] ?? '', $scriptname);
+    $route = preg_replace('@^' . $scriptname . '@', '', $server['REQUEST_URI'] ?? '');
     if (! empty($server['QUERY_STRING'])) {
         return index_url($server) . $route . '?' . $server['QUERY_STRING'];
     }
index e16dd0f43effa6921b6238f0546e7357c9cea188..826604e77204f3726862890d0478ad5b448f7199 100644 (file)
@@ -39,13 +39,23 @@ class LegacyController extends ShaarliVisitorController
     /** Legacy route: ?post= */
     public function post(Request $request, Response $response): Response
     {
-        $parameters = count($request->getQueryParams()) > 0 ? '?' . http_build_query($request->getQueryParams()) : '';
         $route = '/admin/shaare';
+        $buildParameters = function (?array $parameters, bool $encode) {
+            if ($encode) {
+                $parameters = array_map('urlencode', $parameters);
+            }
+
+            return count($parameters) > 0 ? '?' . http_build_query($parameters) : '';
+        };
+
 
         if (!$this->container->loginManager->isLoggedIn()) {
+            $parameters = $buildParameters($request->getQueryParams(), true);
             return $this->redirect($response, '/login?returnurl='. $this->getBasePath() . $route . $parameters);
         }
 
+        $parameters = $buildParameters($request->getQueryParams(), false);
+
         return $this->redirect($response, $route . $parameters);
     }
 
index cea99154cd5885ad495156fd8cfcf68c746f89a5..0449c7e11db4e062ee75352958bd646363e7e4dd 100644 (file)
@@ -17,15 +17,15 @@ class LegacyRouter
 
     public static $PAGE_PICWALL = 'picwall';
 
-    public static $PAGE_TAGCLOUD = 'tagcloud';
+    public static $PAGE_TAGCLOUD = 'tag.cloud';
 
-    public static $PAGE_TAGLIST = 'taglist';
+    public static $PAGE_TAGLIST = 'tag.list';
 
     public static $PAGE_DAILY = 'daily';
 
-    public static $PAGE_FEED_ATOM = 'atom';
+    public static $PAGE_FEED_ATOM = 'feed.atom';
 
-    public static $PAGE_FEED_RSS = 'rss';
+    public static $PAGE_FEED_RSS = 'feed.rss';
 
     public static $PAGE_TOOLS = 'tools';
 
@@ -37,7 +37,7 @@ class LegacyRouter
 
     public static $PAGE_ADDLINK = 'addlink';
 
-    public static $PAGE_EDITLINK = 'edit_link';
+    public static $PAGE_EDITLINK = 'editlink';
 
     public static $PAGE_DELETELINK = 'delete_link';
 
@@ -60,128 +60,4 @@ class LegacyRouter
     public static $PAGE_THUMBS_UPDATE = 'thumbs_update';
 
     public static $GET_TOKEN = 'token';
-
-    /**
-     * Reproducing renderPage() if hell, to avoid regression.
-     *
-     * This highlights how bad this needs to be rewrite,
-     * but let's focus on plugins for now.
-     *
-     * @param string $query    $_SERVER['QUERY_STRING'].
-     * @param array  $get      $_SERVER['GET'].
-     * @param bool   $loggedIn true if authenticated user.
-     *
-     * @return string page found.
-     */
-    public static function findPage($query, $get, $loggedIn)
-    {
-        $loggedIn = ($loggedIn === true) ? true : false;
-
-        if (empty($query) && !isset($get['edit_link']) && !isset($get['post'])) {
-            return self::$PAGE_LINKLIST;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_LOGIN) && $loggedIn === false) {
-            return self::$PAGE_LOGIN;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_PICWALL)) {
-            return self::$PAGE_PICWALL;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_TAGCLOUD)) {
-            return self::$PAGE_TAGCLOUD;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_TAGLIST)) {
-            return self::$PAGE_TAGLIST;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_OPENSEARCH)) {
-            return self::$PAGE_OPENSEARCH;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_DAILY)) {
-            return self::$PAGE_DAILY;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_FEED_ATOM)) {
-            return self::$PAGE_FEED_ATOM;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_FEED_RSS)) {
-            return self::$PAGE_FEED_RSS;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_THUMBS_UPDATE)) {
-            return self::$PAGE_THUMBS_UPDATE;
-        }
-
-        if (startsWith($query, 'do=' . self::$AJAX_THUMB_UPDATE)) {
-            return self::$AJAX_THUMB_UPDATE;
-        }
-
-        // At this point, only loggedin pages.
-        if (!$loggedIn) {
-            return self::$PAGE_LINKLIST;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_TOOLS)) {
-            return self::$PAGE_TOOLS;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_CHANGEPASSWORD)) {
-            return self::$PAGE_CHANGEPASSWORD;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_CONFIGURE)) {
-            return self::$PAGE_CONFIGURE;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_CHANGETAG)) {
-            return self::$PAGE_CHANGETAG;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_ADDLINK)) {
-            return self::$PAGE_ADDLINK;
-        }
-
-        if (isset($get['edit_link']) || isset($get['post'])) {
-            return self::$PAGE_EDITLINK;
-        }
-
-        if (isset($get['delete_link'])) {
-            return self::$PAGE_DELETELINK;
-        }
-
-        if (isset($get[self::$PAGE_CHANGE_VISIBILITY])) {
-            return self::$PAGE_CHANGE_VISIBILITY;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_PINLINK)) {
-            return self::$PAGE_PINLINK;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_EXPORT)) {
-            return self::$PAGE_EXPORT;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_IMPORT)) {
-            return self::$PAGE_IMPORT;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_PLUGINSADMIN)) {
-            return self::$PAGE_PLUGINSADMIN;
-        }
-
-        if (startsWith($query, 'do=' . self::$PAGE_SAVE_PLUGINSADMIN)) {
-            return self::$PAGE_SAVE_PLUGINSADMIN;
-        }
-
-        if (startsWith($query, 'do=' . self::$GET_TOKEN)) {
-            return self::$GET_TOKEN;
-        }
-
-        return self::$PAGE_LINKLIST;
-    }
 }
index 2d93cb3a2173c58bada5803b8ca4fd522819991f..1b2197c9d8d0aa1af56d44842ed18c3fa4f619de 100644 (file)
@@ -100,16 +100,17 @@ class PluginManager
      */
     public function executeHooks($hook, &$data, $params = array())
     {
-        if (!empty($params['target'])) {
-            $data['_PAGE_'] = $params['target'];
-        }
-
-        if (isset($params['loggedin'])) {
-            $data['_LOGGEDIN_'] = $params['loggedin'];
-        }
-
-        if (isset($params['basePath'])) {
-            $data['_BASE_PATH_'] = $params['basePath'];
+        $metadataParameters = [
+            'target' => '_PAGE_',
+            'loggedin' => '_LOGGEDIN_',
+            'basePath' => '_BASE_PATH_',
+            'bookmarkService' => '_BOOKMARK_SERVICE_',
+        ];
+
+        foreach ($metadataParameters as $parameter => $metaKey) {
+            if (array_key_exists($parameter, $params)) {
+                $data[$metaKey] = $params[$parameter];
+            }
         }
 
         foreach ($this->loadedPlugins as $plugin) {
@@ -124,6 +125,10 @@ class PluginManager
                 }
             }
         }
+
+        foreach ($metadataParameters as $metaKey) {
+            unset($data[$metaKey]);
+        }
     }
 
     /**
index c52e3b76143530343f5da67ce32e9f74a805d236..41b357dd72caccc9fe0525b29d3dbc2a31876db2 100644 (file)
@@ -137,7 +137,7 @@ class PageBuilder
         $this->tpl->assign('language', $this->conf->get('translation.language'));
 
         if ($this->bookmarkService !== null) {
-            $this->tpl->assign('tags', $this->bookmarkService->bookmarksCountPerTag());
+            $this->tpl->assign('tags', escape($this->bookmarkService->bookmarksCountPerTag()));
         }
 
         $this->tpl->assign(
index 2793882349ad9fd1503eef0bf5baf5681f9f2b0f..be986ae015ed7aef888814bd5757f0fe434125cc 100644 (file)
@@ -10,7 +10,7 @@ import Awesomplete from 'awesomplete';
  * @returns Found element or null.
  */
 function findParent(element, tagName, attributes) {
-  const parentMatch = key => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1;
+  const parentMatch = (key) => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1;
   while (element) {
     if (element.tagName.toLowerCase() === tagName) {
       if (Object.keys(attributes).find(parentMatch)) {
@@ -101,7 +101,7 @@ function updateAwesompleteList(selector, tags, instances) {
  * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript
  */
 function htmlEntities(str) {
-  return str.replace(/[\u00A0-\u9999<>&]/gim, i => `&#${i.charCodeAt(0)};`);
+  return str.replace(/[\u00A0-\u9999<>&]/gim, (i) => `&#${i.charCodeAt(0)};`);
 }
 
 /**
@@ -194,8 +194,8 @@ function removeClass(element, classname) {
 function init(description) {
   function resize() {
     /* Fix jumpy resizing: https://stackoverflow.com/a/18262927/1484919 */
-    const scrollTop = window.pageYOffset ||
-      (document.documentElement || document.body.parentNode || document.body).scrollTop;
+    const scrollTop = window.pageYOffset
+      || (document.documentElement || document.body.parentNode || document.body).scrollTop;
 
     description.style.height = 'auto';
     description.style.height = `${description.scrollHeight + 10}px`;
@@ -490,9 +490,10 @@ function init(description) {
           });
         });
 
-        const ids = links.map(item => item.id);
-        window.location =
-          `${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}`;
+        const ids = links.map((item) => item.id);
+        window.location = (
+          `${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}`
+        );
       });
     });
   }
@@ -554,6 +555,7 @@ function init(description) {
       }
       const refreshedToken = document.getElementById('token').value;
       const fromtag = block.getAttribute('data-tag');
+      const fromtagUrl = block.getAttribute('data-tag-url');
       const xhr = new XMLHttpRequest();
       xhr.open('POST', `${basePath}/admin/tags`);
       xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
@@ -563,6 +565,7 @@ function init(description) {
           location.reload();
         } else {
           block.setAttribute('data-tag', totag);
+          block.setAttribute('data-tag-url', encodeURIComponent(totag));
           input.setAttribute('name', totag);
           input.setAttribute('value', totag);
           findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none';
@@ -570,16 +573,19 @@ function init(description) {
           block
             .querySelector('a.tag-link')
             .setAttribute('href', `${basePath}/?searchtags=${encodeURIComponent(totag)}`);
+          block
+            .querySelector('a.count')
+            .setAttribute('href', `${basePath}/add-tag/${encodeURIComponent(totag)}`);
           block
             .querySelector('a.rename-tag')
             .setAttribute('href', `${basePath}/admin/tags?fromtag=${encodeURIComponent(totag)}`);
 
           // Refresh awesomplete values
-          existingTags = existingTags.map(tag => (tag === fromtag ? totag : tag));
+          existingTags = existingTags.map((tag) => (tag === fromtag ? totag : tag));
           awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes);
         }
       };
-      xhr.send(`renametag=1&fromtag=${encodeURIComponent(fromtag)}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`);
+      xhr.send(`renametag=1&fromtag=${fromtagUrl}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`);
       refreshToken(basePath);
     });
   });
@@ -602,6 +608,7 @@ function init(description) {
       event.preventDefault();
       const block = findParent(event.target, 'div', { class: 'tag-list-item' });
       const tag = block.getAttribute('data-tag');
+      const tagUrl = block.getAttribute('data-tag-url');
       const refreshedToken = document.getElementById('token').value;
 
       if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) {
@@ -611,10 +618,10 @@ function init(description) {
         xhr.onload = () => {
           block.remove();
         };
-        xhr.send(encodeURI(`deletetag=1&fromtag=${tag}&token=${refreshedToken}`));
+        xhr.send(`deletetag=1&fromtag=${tagUrl}&token=${refreshedToken}`);
         refreshToken(basePath);
 
-        existingTags = existingTags.filter(tagItem => tagItem !== tag);
+        existingTags = existingTags.filter((tagItem) => tagItem !== tag);
         awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes);
       }
     });
index 7ab09d3f2e313657f6682bf211b7d9462c6a88e7..a528adb0dbe7931ea79c0cf0875b85951a3038c8 100644 (file)
@@ -69,20 +69,22 @@ pre {
   font-family: 'Roboto';
   font-weight: 400;
   font-style: normal;
-  src: local('Roboto'),
-  local('Roboto-Regular'),
-  url('../fonts/Roboto-Regular.woff2') format('woff2'),
-  url('../fonts/Roboto-Regular.woff') format('woff');
+  src:
+    local('Roboto'),
+    local('Roboto-Regular'),
+    url('../fonts/Roboto-Regular.woff2') format('woff2'),
+    url('../fonts/Roboto-Regular.woff') format('woff');
 }
 
 @font-face {
   font-family: 'Roboto';
   font-weight: 700;
   font-style: normal;
-  src: local('Roboto'),
-  local('Roboto-Bold'),
-  url('../fonts/Roboto-Bold.woff2') format('woff2'),
-  url('../fonts/Roboto-Bold.woff') format('woff');
+  src:
+    local('Roboto'),
+    local('Roboto-Bold'),
+    url('../fonts/Roboto-Bold.woff2') format('woff2'),
+    url('../fonts/Roboto-Bold.woff') format('woff');
 }
 
 body,
@@ -375,7 +377,7 @@ body,
 }
 
 @media screen and (max-width: 64em) {
-  .header-search ,
+  .header-search,
   .header-search * {
     visibility: hidden;
   }
@@ -554,7 +556,6 @@ body,
   color: $dark-grey;
   font-size: .9em;
 
-
   a {
     display: inline-block;
     margin: 3px 0;
@@ -620,7 +621,7 @@ body,
     &.selected {
       background: var(--main-color);
       color: $white;
-     }
+    }
   }
 
   input {
@@ -1557,11 +1558,11 @@ form {
   text-align: center;
 
   a {
+    background: $almost-white;
     display: inline-block;
-    margin: 0 15px;
+    padding: 5px;
     text-decoration: none;
-    color: $white;
-    font-weight: bold;
+    color: $dark-grey;
   }
 }
 
@@ -1609,13 +1610,14 @@ form {
 
   > div {
     border-radius: 10px;
-    background: repeating-linear-gradient(
-      -45deg,
-      $almost-white,
-      $almost-white 6px,
-      var(--background-color) 6px,
-      var(--background-color) 12px
-    );
+    background:
+      repeating-linear-gradient(
+        -45deg,
+        $almost-white,
+        $almost-white 6px,
+        var(--background-color) 6px,
+        var(--background-color) 12px
+      );
     width: 0%;
     height: 10px;
   }
index 87c440c86f702958224c7c5a334802ca7f817196..1688dce07217a781c8edf6c58368d47b639a9df0 100644 (file)
@@ -746,8 +746,6 @@ a.bigbutton, #pageheader a.bigbutton {
     text-align: left;
     background-color: transparent;
     background-color: rgba(0, 0, 0, 0.4);
-    /* FF3+, Saf3+, Opera 10.10+, Chrome, IE9 */
-    filter: progid: DXImageTransform.Microsoft.gradient(startColorstr=#66000000, endColorstr=#66000000);
     /* IE6\96IE9 */
     text-shadow: 2px 2px 1px #000000;
 }
index 738d9f5887f1a72b5b5b538ec6e03a7687db05df..7e675623c051abf9e917becbbf57e9107cb580f9 100644 (file)
@@ -10,6 +10,7 @@
     },
     "keywords": ["bookmark", "link", "share", "web"],
     "config": {
+        "sort-packages": true,
         "platform": {
             "php": "7.1.29"
         }
         "php": ">=7.1",
         "ext-json": "*",
         "ext-zlib": "*",
-        "shaarli/netscape-bookmark-parser": "^2.1",
-        "erusev/parsedown": "^1.6",
-        "slim/slim": "^3.0",
         "arthurhoaro/web-thumbnailer": "^2.0",
+        "erusev/parsedown": "^1.6",
+        "erusev/parsedown-extra": "^0.8.1",
+        "gettext/gettext": "^4.4",
         "pubsubhubbub/publisher": "dev-master",
-        "gettext/gettext": "^4.4"
+        "shaarli/netscape-bookmark-parser": "^2.1",
+        "slim/slim": "^3.0"
     },
     "require-dev": {
         "roave/security-advisories": "dev-master",
-        "phpunit/phpcov": "*",
-        "phpunit/phpunit": "^7.5",
-        "squizlabs/php_codesniffer": "3.*"
+        "squizlabs/php_codesniffer": "3.*",
+        "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
     },
     "suggest": {
         "ext-curl": "Allows fetching web pages and thumbnails in a more robust way",
index ae7a9269f61e9b8c41351a96a9877f2004a36ce4..e02491ff3f7c70db800e7433d16461faac5866e4 100644 (file)
@@ -4,29 +4,31 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "37e420b4b6e9fa74b27e127dd422d9a6",
+    "content-hash": "f84918821b0dceb0cd569875c0418bb8",
     "packages": [
         {
             "name": "arthurhoaro/web-thumbnailer",
-            "version": "v2.0.1",
+            "version": "v2.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ArthurHoaro/web-thumbnailer.git",
-                "reference": "4aa27a1b54b9823341fedd7ca2dcfb11a6b3186a"
+                "reference": "39bfd4f3136d9e6096496b9720e877326cfe4775"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/4aa27a1b54b9823341fedd7ca2dcfb11a6b3186a",
-                "reference": "4aa27a1b54b9823341fedd7ca2dcfb11a6b3186a",
+                "url": "https://api.github.com/repos/ArthurHoaro/web-thumbnailer/zipball/39bfd4f3136d9e6096496b9720e877326cfe4775",
+                "reference": "39bfd4f3136d9e6096496b9720e877326cfe4775",
                 "shasum": ""
             },
             "require": {
                 "php": ">=7.1",
-                "phpunit/php-text-template": "^1.2"
+                "phpunit/php-text-template": "^1.2 || ^2.0"
             },
             "require-dev": {
+                "gskema/phpcs-type-sniff": "^0.13.1",
                 "php-coveralls/php-coveralls": "^2.0",
-                "phpunit/phpunit": "^7.0 || ^8.0",
+                "phpstan/phpstan": "^0.12.9",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
                 "squizlabs/php_codesniffer": "^3.0"
             },
             "type": "library",
                 }
             ],
             "description": "PHP library which will retrieve a thumbnail for any given URL",
-            "time": "2020-01-17T19:42:49+00:00"
+            "support": {
+                "issues": "https://github.com/ArthurHoaro/web-thumbnailer/issues",
+                "source": "https://github.com/ArthurHoaro/web-thumbnailer/tree/v2.0.3"
+            },
+            "time": "2020-09-29T15:51:03+00:00"
         },
         {
             "name": "erusev/parsedown",
                 "markdown",
                 "parser"
             ],
+            "support": {
+                "issues": "https://github.com/erusev/parsedown/issues",
+                "source": "https://github.com/erusev/parsedown/tree/1.7.x"
+            },
             "time": "2019-12-30T22:54:17+00:00"
         },
+        {
+            "name": "erusev/parsedown-extra",
+            "version": "0.8.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/erusev/parsedown-extra.git",
+                "reference": "91ac3ff98f0cea243bdccc688df43810f044dcef"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/91ac3ff98f0cea243bdccc688df43810f044dcef",
+                "reference": "91ac3ff98f0cea243bdccc688df43810f044dcef",
+                "shasum": ""
+            },
+            "require": {
+                "erusev/parsedown": "^1.7.4"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "ParsedownExtra": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Emanuil Rusev",
+                    "email": "hello@erusev.com",
+                    "homepage": "http://erusev.com"
+                }
+            ],
+            "description": "An extension of Parsedown that adds support for Markdown Extra.",
+            "homepage": "https://github.com/erusev/parsedown-extra",
+            "keywords": [
+                "markdown",
+                "markdown extra",
+                "parsedown",
+                "parser"
+            ],
+            "support": {
+                "issues": "https://github.com/erusev/parsedown-extra/issues",
+                "source": "https://github.com/erusev/parsedown-extra/tree/0.8.x"
+            },
+            "time": "2019-12-30T23:20:37+00:00"
+        },
         {
             "name": "gettext/gettext",
             "version": "v4.8.2",
                 "po",
                 "translation"
             ],
+            "support": {
+                "email": "oom@oscarotero.com",
+                "issues": "https://github.com/oscarotero/Gettext/issues",
+                "source": "https://github.com/php-gettext/Gettext/tree/v4.8.2"
+            },
             "time": "2019-12-02T10:21:14+00:00"
         },
         {
                 "translations",
                 "unicode"
             ],
+            "support": {
+                "issues": "https://github.com/php-gettext/Languages/issues",
+                "source": "https://github.com/php-gettext/Languages/tree/2.6.0"
+            },
             "time": "2019-11-13T10:30:21+00:00"
         },
         {
             "keywords": [
                 "logging"
             ],
+            "support": {
+                "issues": "https://github.com/katzgrau/KLogger/issues",
+                "source": "https://github.com/katzgrau/KLogger/tree/master"
+            },
             "time": "2016-11-07T19:29:14+00:00"
         },
         {
                 "router",
                 "routing"
             ],
+            "support": {
+                "issues": "https://github.com/nikic/FastRoute/issues",
+                "source": "https://github.com/nikic/FastRoute/tree/master"
+            },
             "time": "2018-02-13T20:26:39+00:00"
         },
         {
             "keywords": [
                 "template"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-text-template/issues",
+                "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
+            },
             "time": "2015-06-21T13:50:34+00:00"
         },
         {
                 "container",
                 "dependency injection"
             ],
+            "support": {
+                "issues": "https://github.com/silexphp/Pimple/issues",
+                "source": "https://github.com/silexphp/Pimple/tree/master"
+            },
             "time": "2018-01-21T07:42:36+00:00"
         },
         {
                 "container-interop",
                 "psr"
             ],
+            "support": {
+                "issues": "https://github.com/php-fig/container/issues",
+                "source": "https://github.com/php-fig/container/tree/master"
+            },
             "time": "2017-02-14T16:28:37+00:00"
         },
         {
                 "request",
                 "response"
             ],
+            "support": {
+                "source": "https://github.com/php-fig/http-message/tree/master"
+            },
             "time": "2016-08-06T14:39:51+00:00"
         },
         {
                 "psr",
                 "psr-3"
             ],
+            "support": {
+                "source": "https://github.com/php-fig/log/tree/1.1.3"
+            },
             "time": "2020-03-23T09:12:05+00:00"
         },
         {
                 "ext-curl": "*",
                 "php": "~5.4 || ~7.0"
             },
+            "default-branch": true,
             "type": "library",
             "autoload": {
                 "psr-4": {
                 "pubsubhubbub",
                 "websub"
             ],
+            "support": {
+                "issues": "https://github.com/pubsubhubbub/php-publisher/issues",
+                "source": "https://github.com/pubsubhubbub/php-publisher/tree/master"
+            },
             "time": "2018-10-09T05:20:28+00:00"
         },
         {
             "name": "shaarli/netscape-bookmark-parser",
-            "version": "v2.1.0",
+            "version": "v2.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/shaarli/netscape-bookmark-parser.git",
-                "reference": "819008ee42c4dd7e45d988176a4a22d6ed689577"
+                "reference": "432a010af2bb1832d6fbc4763e6b0100b980a1df"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/819008ee42c4dd7e45d988176a4a22d6ed689577",
-                "reference": "819008ee42c4dd7e45d988176a4a22d6ed689577",
+                "url": "https://api.github.com/repos/shaarli/netscape-bookmark-parser/zipball/432a010af2bb1832d6fbc4763e6b0100b980a1df",
+                "reference": "432a010af2bb1832d6fbc4763e6b0100b980a1df",
                 "shasum": ""
             },
             "require": {
                 "bookmark",
                 "link",
                 "netscape",
-                "parser"
+                "parse"
             ],
-            "time": "2018-10-06T14:43:38+00:00"
+            "support": {
+                "issues": "https://github.com/shaarli/netscape-bookmark-parser/issues",
+                "source": "https://github.com/shaarli/netscape-bookmark-parser/tree/v2.2.0"
+            },
+            "time": "2020-06-06T15:53:53+00:00"
         },
         {
             "name": "slim/slim",
                 "micro",
                 "router"
             ],
+            "support": {
+                "issues": "https://github.com/slimphp/Slim/issues",
+                "source": "https://github.com/slimphp/Slim/tree/3.x"
+            },
             "time": "2019-11-28T17:40:33+00:00"
         }
     ],
     "packages-dev": [
         {
             "name": "doctrine/instantiator",
-            "version": "1.3.0",
+            "version": "1.3.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/doctrine/instantiator.git",
-                "reference": "ae466f726242e637cebdd526a7d991b9433bacf1"
+                "reference": "f350df0268e904597e3bd9c4685c53e0e333feea"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1",
-                "reference": "ae466f726242e637cebdd526a7d991b9433bacf1",
+                "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea",
+                "reference": "f350df0268e904597e3bd9c4685c53e0e333feea",
                 "shasum": ""
             },
             "require": {
-                "php": "^7.1"
+                "php": "^7.1 || ^8.0"
             },
             "require-dev": {
                 "doctrine/coding-standard": "^6.0",
                 "constructor",
                 "instantiate"
             ],
-            "time": "2019-10-21T16:45:58+00:00"
+            "support": {
+                "issues": "https://github.com/doctrine/instantiator/issues",
+                "source": "https://github.com/doctrine/instantiator/tree/1.3.x"
+            },
+            "funding": [
+                {
+                    "url": "https://www.doctrine-project.org/sponsorship.html",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://www.patreon.com/phpdoctrine",
+                    "type": "patreon"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-05-29T17:27:14+00:00"
         },
         {
             "name": "myclabs/deep-copy",
-            "version": "1.9.5",
+            "version": "1.10.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef"
+                "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/b2c28789e80a97badd14145fda39b545d83ca3ef",
-                "reference": "b2c28789e80a97badd14145fda39b545d83ca3ef",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
+                "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5",
                 "shasum": ""
             },
             "require": {
-                "php": "^7.1"
+                "php": "^7.1 || ^8.0"
             },
             "replace": {
                 "myclabs/deep-copy": "self.version"
                 "object",
                 "object graph"
             ],
-            "time": "2020-01-17T21:11:47+00:00"
+            "support": {
+                "issues": "https://github.com/myclabs/DeepCopy/issues",
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.x"
+            },
+            "funding": [
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-06-29T13:22:24+00:00"
         },
         {
             "name": "phar-io/manifest",
                 }
             ],
             "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
+            "support": {
+                "issues": "https://github.com/phar-io/manifest/issues",
+                "source": "https://github.com/phar-io/manifest/tree/master"
+            },
             "time": "2018-07-08T19:23:20+00:00"
         },
         {
                 }
             ],
             "description": "Library for handling version information and constraints",
+            "support": {
+                "issues": "https://github.com/phar-io/version/issues",
+                "source": "https://github.com/phar-io/version/tree/master"
+            },
             "time": "2018-07-08T19:19:57+00:00"
         },
         {
                 "reflection",
                 "static analysis"
             ],
+            "support": {
+                "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
+                "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
+            },
             "time": "2020-04-27T09:25:28+00:00"
         },
         {
                 }
             ],
             "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
+            "support": {
+                "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
+                "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/4.x"
+            },
             "time": "2019-12-28T18:55:12+00:00"
         },
         {
                 }
             ],
             "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
+            "support": {
+                "issues": "https://github.com/phpDocumentor/TypeResolver/issues",
+                "source": "https://github.com/phpDocumentor/TypeResolver/tree/0.7.2"
+            },
             "time": "2019-08-22T18:11:29+00:00"
         },
         {
                 "spy",
                 "stub"
             ],
+            "support": {
+                "issues": "https://github.com/phpspec/prophecy/issues",
+                "source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
+            },
             "time": "2020-03-05T15:02:03+00:00"
         },
         {
                 "testing",
                 "xunit"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/master"
+            },
             "time": "2018-10-31T16:06:48+00:00"
         },
         {
                 "filesystem",
                 "iterator"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
+                "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.2"
+            },
             "time": "2018-09-13T20:33:42+00:00"
         },
         {
             "keywords": [
                 "timer"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-timer/issues",
+                "source": "https://github.com/sebastianbergmann/php-timer/tree/master"
+            },
             "time": "2019-06-07T04:22:29+00:00"
         },
         {
             "keywords": [
                 "tokenizer"
             ],
-            "time": "2019-09-17T06:23:10+00:00"
-        },
-        {
-            "name": "phpunit/phpcov",
-            "version": "5.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/phpcov.git",
-                "reference": "72fb974e6fe9b39d7e0b0d44061d2ba4c49ee0b8"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpcov/zipball/72fb974e6fe9b39d7e0b0d44061d2ba4c49ee0b8",
-                "reference": "72fb974e6fe9b39d7e0b0d44061d2ba4c49ee0b8",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1",
-                "phpunit/php-code-coverage": "^6.0",
-                "phpunit/phpunit": "^7.0",
-                "sebastian/diff": "^3.0",
-                "sebastian/finder-facade": "^1.1",
-                "sebastian/version": "^2.0",
-                "symfony/console": "^3.0 || ^4.0"
-            },
-            "bin": [
-                "phpcov"
-            ],
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "5.0-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
+                "source": "https://github.com/sebastianbergmann/php-token-stream/tree/3.1.1"
             },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "CLI frontend for php-code-coverage",
-            "homepage": "https://github.com/sebastianbergmann/phpcov",
-            "time": "2018-02-04T10:18:50+00:00"
+            "abandoned": true,
+            "time": "2019-09-17T06:23:10+00:00"
         },
         {
             "name": "phpunit/phpunit",
                 "testing",
                 "xunit"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/phpunit/issues",
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/7.5.20"
+            },
             "time": "2020-01-08T08:45:45+00:00"
         },
         {
             "source": {
                 "type": "git",
                 "url": "https://github.com/Roave/SecurityAdvisories.git",
-                "reference": "5a342e2dc0408d026b97ee3176b5b406e54e3766"
+                "reference": "ba5d234b3a1559321b816b64aafc2ce6728799ff"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/5a342e2dc0408d026b97ee3176b5b406e54e3766",
-                "reference": "5a342e2dc0408d026b97ee3176b5b406e54e3766",
+                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/ba5d234b3a1559321b816b64aafc2ce6728799ff",
+                "reference": "ba5d234b3a1559321b816b64aafc2ce6728799ff",
                 "shasum": ""
             },
             "conflict": {
                 "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1",
                 "amphp/artax": "<1.0.6|>=2,<2.0.6",
                 "amphp/http": "<1.0.1",
+                "amphp/http-client": ">=4,<4.4",
                 "api-platform/core": ">=2.2,<2.2.10|>=2.3,<2.3.6",
                 "asymmetricrypt/asymmetricrypt": ">=0,<9.9.99",
                 "aws/aws-sdk-php": ">=3,<3.2.1",
                 "bagisto/bagisto": "<0.1.5",
-                "barrelstrength/sprout-base-email": "<3.9",
-                "bolt/bolt": "<3.6.10",
+                "barrelstrength/sprout-base-email": "<1.2.7",
+                "barrelstrength/sprout-forms": "<3.9",
+                "baserproject/basercms": ">=4,<=4.3.6",
+                "bolt/bolt": "<3.7.1",
                 "brightlocal/phpwhois": "<=4.2.5",
                 "buddypress/buddypress": "<5.1.2",
                 "bugsnag/bugsnag-laravel": ">=2,<2.0.2",
                 "composer/composer": "<=1-alpha.11",
                 "contao-components/mediaelement": ">=2.14.2,<2.21.1",
                 "contao/core": ">=2,<3.5.39",
-                "contao/core-bundle": ">=4,<4.4.46|>=4.5,<4.8.6",
+                "contao/core-bundle": ">=4,<4.4.52|>=4.5,<4.9.6|= 4.10.0",
                 "contao/listing-bundle": ">=4,<4.4.8",
                 "datadog/dd-trace": ">=0.30,<0.30.2",
                 "david-garcia/phpwhois": "<=4.3.1",
+                "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1",
                 "doctrine/annotations": ">=1,<1.2.7",
                 "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2",
                 "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1",
                 "doctrine/mongodb-odm": ">=1,<1.0.2",
                 "doctrine/mongodb-odm-bundle": ">=2,<3.0.1",
                 "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1",
-                "dolibarr/dolibarr": "<=10.0.6",
+                "dolibarr/dolibarr": "<11.0.4",
                 "dompdf/dompdf": ">=0.6,<0.6.2",
-                "drupal/core": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4",
-                "drupal/drupal": ">=7,<7.69|>=8,<8.7.12|>=8.8,<8.8.4",
+                "drupal/core": ">=7,<7.73|>=8,<8.8.10|>=8.9,<8.9.6|>=9,<9.0.6",
+                "drupal/drupal": ">=7,<7.73|>=8,<8.8.10|>=8.9,<8.9.6|>=9,<9.0.6",
                 "endroid/qr-code-bundle": "<3.4.2",
                 "enshrined/svg-sanitize": "<0.13.1",
                 "erusev/parsedown": "<1.7.2",
                 "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1|>=5.4,<5.4.11.1|>=2017.12,<2017.12.0.1",
                 "ezsystems/ezplatform": ">=1.7,<1.7.9.1|>=1.13,<1.13.5.1|>=2.5,<2.5.4",
                 "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6",
-                "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2",
+                "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1",
+                "ezsystems/ezplatform-kernel": ">=1,<1.0.2.1",
                 "ezsystems/ezplatform-user": ">=1,<1.0.1",
-                "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.1|>=6,<6.7.9.1|>=6.8,<6.13.6.2|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.6.2",
-                "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.1|>=2011,<2017.12.7.2|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.4.2",
+                "ezsystems/ezpublish-kernel": ">=5.3,<5.3.12.1|>=5.4,<5.4.14.2|>=6,<6.7.9.1|>=6.8,<6.13.6.3|>=7,<7.2.4.1|>=7.3,<7.3.2.1|>=7.5,<7.5.7.1",
+                "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.6|>=5.4,<5.4.14.2|>=2011,<2017.12.7.3|>=2018.6,<2018.6.1.4|>=2018.9,<2018.9.1.3|>=2019.3,<2019.3.5.1",
+                "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3",
                 "ezsystems/repository-forms": ">=2.3,<2.3.2.1",
                 "ezyang/htmlpurifier": "<4.1.1",
                 "firebase/php-jwt": "<2",
                 "friendsofsymfony/oauth2-php": "<1.3",
                 "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2",
                 "friendsofsymfony/user-bundle": ">=1.2,<1.3.5",
+                "friendsoftypo3/mediace": ">=7.6.2,<7.6.5",
                 "fuel/core": "<1.8.1",
                 "getgrav/grav": "<1.7-beta.8",
+                "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3",
                 "gree/jose": "<=2.2",
                 "gregwar/rst": "<1.0.3",
                 "guzzlehttp/guzzle": ">=4-rc.2,<4.2.4|>=5,<5.3.1|>=6,<6.2.1",
                 "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10",
-                "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30",
-                "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29",
+                "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.31|>=7,<7.22.4",
+                "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29|>=5.5,<=5.5.44|>=6,<6.18.34|>=7,<7.23.2",
                 "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
                 "illuminate/view": ">=7,<7.1.2",
                 "ivankristianto/phpwhois": "<=4.3",
                 "joomla/session": "<1.3.1",
                 "jsmitty12/phpwhois": "<5.1",
                 "kazist/phpwhois": "<=4.2.6",
+                "kitodo/presentation": "<3.1.2",
                 "kreait/firebase-php": ">=3.2,<3.8.1",
                 "la-haute-societe/tcpdf": "<6.2.22",
-                "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.42|>=5.6,<5.6.30|>=7,<7.1.2",
+                "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.99999|>=4.2,<=4.2.99999|>=5,<=5.0.99999|>=5.1,<=5.1.99999|>=5.2,<=5.2.99999|>=5.3,<=5.3.99999|>=5.4,<=5.4.99999|>=5.5,<=5.5.49|>=5.6,<=5.6.99999|>=5.7,<=5.7.99999|>=5.8,<=5.8.99999|>=6,<6.18.34|>=7,<7.23.2",
                 "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
                 "league/commonmark": "<0.18.3",
                 "librenms/librenms": "<1.53",
+                "livewire/livewire": ">2.2.4,<2.2.6",
                 "magento/community-edition": ">=2,<2.2.10|>=2.3,<2.3.3",
                 "magento/magento1ce": "<1.9.4.3",
                 "magento/magento1ee": ">=1,<1.14.4.3",
                 "magento/product-community-edition": ">=2,<2.2.10|>=2.3,<2.3.2-p.2",
+                "marcwillmann/turn": "<0.3.3",
+                "mittwald/typo3_forum": "<1.2.1",
                 "monolog/monolog": ">=1.8,<1.12",
                 "namshi/jose": "<2.2",
+                "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6",
+                "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13",
+                "nystudio107/craft-seomatic": "<3.3",
                 "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1",
+                "october/backend": ">=1.0.319,<1.0.467",
+                "october/cms": ">=1.0.319,<1.0.466",
+                "october/october": ">=1.0.319,<1.0.466",
+                "october/rain": ">=1.0.319,<1.0.468",
                 "onelogin/php-saml": "<2.10.4",
                 "oneup/uploader-bundle": "<1.9.3|>=2,<2.1.5",
                 "openid/php-openid": "<2.3",
+                "openmage/magento-lts": "<19.4.6|>=20,<20.0.2",
                 "oro/crm": ">=1.7,<1.7.4",
                 "oro/platform": ">=1.7,<1.7.4",
                 "padraic/humbug_get_contents": "<1.1.2",
                 "paragonie/random_compat": "<2",
                 "paypal/merchant-sdk-php": "<3.12",
                 "pear/archive_tar": "<1.4.4",
+                "personnummer/personnummer": "<3.0.2",
                 "phpfastcache/phpfastcache": ">=5,<5.0.13",
-                "phpmailer/phpmailer": ">=5,<5.2.27|>=6,<6.0.6",
+                "phpmailer/phpmailer": "<6.1.6",
+                "phpmussel/phpmussel": ">=1,<1.6",
                 "phpmyadmin/phpmyadmin": "<4.9.2",
                 "phpoffice/phpexcel": "<1.8.2",
                 "phpoffice/phpspreadsheet": "<1.8",
                 "phpxmlrpc/extras": "<0.6.1",
                 "pimcore/pimcore": "<6.3",
                 "prestashop/autoupgrade": ">=4,<4.10.1",
+                "prestashop/contactform": ">1.0.1,<4.3",
                 "prestashop/gamification": "<2.3.2",
                 "prestashop/ps_facetedsearch": "<3.4.1",
                 "privatebin/privatebin": "<1.2.2|>=1.3,<1.3.2",
                 "propel/propel": ">=2-alpha.1,<=2-alpha.7",
                 "propel/propel1": ">=1,<=1.7.1",
+                "pterodactyl/panel": "<0.7.19|>=1-rc.0,<=1-rc.6",
                 "pusher/pusher-php-server": "<2.2.1",
+                "rainlab/debugbar-plugin": "<3.1",
                 "robrichards/xmlseclibs": "<3.0.4",
+                "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1",
                 "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9",
                 "scheb/two-factor-bundle": ">=0,<3.26|>=4,<4.11",
                 "sensiolabs/connect": "<4.2.3",
                 "serluck/phpwhois": "<=4.2.6",
+                "shopware/core": "<=6.3.1",
+                "shopware/platform": "<=6.3.1",
                 "shopware/shopware": "<5.3.7",
                 "silverstripe/admin": ">=1.0.3,<1.0.4|>=1.1,<1.1.1",
                 "silverstripe/assets": ">=1,<1.4.7|>=1.5,<1.5.2",
                 "silverstripe/cms": "<4.3.6|>=4.4,<4.4.4",
                 "silverstripe/comments": ">=1.3,<1.9.99|>=2,<2.9.99|>=3,<3.1.1",
                 "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3",
-                "silverstripe/framework": "<4.4.5|>=4.5,<4.5.2",
-                "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2",
+                "silverstripe/framework": "<4.4.7|>=4.5,<4.5.4",
+                "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.1.2|>=3.2,<3.2.4",
                 "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1",
                 "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4",
                 "silverstripe/subsites": ">=2,<2.1.1",
                 "ssddanbrown/bookstack": "<0.29.2",
                 "stormpath/sdk": ">=0,<9.9.99",
                 "studio-42/elfinder": "<2.1.49",
+                "sulu/sulu": "<1.6.34|>=2,<2.0.10|>=2.1,<2.1.1",
                 "swiftmailer/swiftmailer": ">=4,<5.4.5",
                 "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2",
                 "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
                 "sylius/grid-bundle": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1",
-                "sylius/resource-bundle": "<1.3.13|>=1.4,<1.4.6|>=1.5,<1.5.1|>=1.6,<1.6.3",
+                "sylius/resource-bundle": "<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4",
                 "sylius/sylius": "<1.3.16|>=1.4,<1.4.12|>=1.5,<1.5.9|>=1.6,<1.6.5",
                 "symbiote/silverstripe-multivaluefield": ">=3,<3.0.99",
                 "symbiote/silverstripe-versionedfiles": "<=2.0.3",
                 "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1",
                 "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
                 "symfony/http-foundation": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
-                "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8",
+                "symfony/http-kernel": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5",
                 "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13",
                 "symfony/mime": ">=4.3,<4.3.8",
                 "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7",
                 "symfony/security-guard": ">=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11",
                 "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
                 "symfony/serializer": ">=2,<2.0.11",
-                "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7",
+                "symfony/symfony": ">=2,<2.8.52|>=3,<3.4.35|>=4,<4.2.12|>=4.3,<4.4.13|>=5,<5.1.5",
                 "symfony/translation": ">=2,<2.0.17",
                 "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3",
                 "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8",
                 "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4",
                 "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7",
+                "t3g/svg-sanitizer": "<1.0.3",
                 "tecnickcom/tcpdf": "<6.2.22",
                 "thelia/backoffice-default-template": ">=2.1,<2.1.2",
                 "thelia/thelia": ">=2.1-beta.1,<2.1.3",
                 "titon/framework": ">=0,<9.9.99",
                 "truckersmp/phpwhois": "<=4.3.1",
                 "twig/twig": "<1.38|>=2,<2.7",
-                "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.17|>=10,<10.4.2",
-                "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.17|>=10,<10.4.2",
+                "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.32|>=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6",
+                "typo3/cms-core": ">=8,<8.7.30|>=9,<9.5.20|>=10,<10.4.6",
                 "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5",
                 "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
                 "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1",
+                "typo3fluid/fluid": ">=2,<2.0.5|>=2.1,<2.1.4|>=2.2,<2.2.1|>=2.3,<2.3.5|>=2.4,<2.4.1|>=2.5,<2.5.5|>=2.6,<2.6.1",
                 "ua-parser/uap-php": "<3.8",
                 "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2",
                 "verot/class.upload.php": "<=1.0.3|>=2,<=2.0.4",
                 "willdurand/js-translation-bundle": "<2.1.1",
                 "yii2mod/yii2-cms": "<1.9.2",
                 "yiisoft/yii": ">=1.1.14,<1.1.15",
-                "yiisoft/yii2": "<2.0.15",
+                "yiisoft/yii2": "<2.0.38",
                 "yiisoft/yii2-bootstrap": "<2.0.4",
                 "yiisoft/yii2-dev": "<2.0.15",
                 "yiisoft/yii2-elasticsearch": "<2.0.5",
                 }
             ],
             "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
-            "time": "2020-05-12T11:18:47+00:00"
+            "support": {
+                "issues": "https://github.com/Roave/SecurityAdvisories/issues",
+                "source": "https://github.com/Roave/SecurityAdvisories/tree/latest"
+            },
+            "funding": [
+                {
+                    "url": "https://github.com/Ocramius",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories",
+                    "type": "tidelift"
+                }
+            ],
+            "time": "2020-10-08T21:02:27+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
             ],
             "description": "Looks up which function or method a line of code belongs to",
             "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
+                "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/master"
+            },
             "time": "2017-03-04T06:30:41+00:00"
         },
         {
                 "compare",
                 "equality"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/comparator/issues",
+                "source": "https://github.com/sebastianbergmann/comparator/tree/master"
+            },
             "time": "2018-07-12T15:12:46+00:00"
         },
         {
                 "unidiff",
                 "unified diff"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/diff/issues",
+                "source": "https://github.com/sebastianbergmann/diff/tree/master"
+            },
             "time": "2019-02-04T06:01:07+00:00"
         },
         {
                 "environment",
                 "hhvm"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/environment/issues",
+                "source": "https://github.com/sebastianbergmann/environment/tree/4.2.3"
+            },
             "time": "2019-11-20T08:46:58+00:00"
         },
         {
                 "export",
                 "exporter"
             ],
-            "time": "2019-09-14T09:02:43+00:00"
-        },
-        {
-            "name": "sebastian/finder-facade",
-            "version": "1.2.3",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/sebastianbergmann/finder-facade.git",
-                "reference": "167c45d131f7fc3d159f56f191a0a22228765e16"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/finder-facade/zipball/167c45d131f7fc3d159f56f191a0a22228765e16",
-                "reference": "167c45d131f7fc3d159f56f191a0a22228765e16",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1",
-                "symfony/finder": "^2.3|^3.0|^4.0|^5.0",
-                "theseer/fdomdocument": "^1.6"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": []
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/exporter/issues",
+                "source": "https://github.com/sebastianbergmann/exporter/tree/master"
             },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sebastian@phpunit.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "FinderFacade is a convenience wrapper for Symfony's Finder component.",
-            "homepage": "https://github.com/sebastianbergmann/finder-facade",
-            "time": "2020-01-16T08:08:45+00:00"
+            "time": "2019-09-14T09:02:43+00:00"
         },
         {
             "name": "sebastian/global-state",
             "keywords": [
                 "global state"
             ],
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/global-state/issues",
+                "source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
+            },
             "time": "2017-04-27T15:39:26+00:00"
         },
         {
             ],
             "description": "Traverses array structures and object graphs to enumerate all referenced objects",
             "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
+                "source": "https://github.com/sebastianbergmann/object-enumerator/tree/master"
+            },
             "time": "2017-08-03T12:35:26+00:00"
         },
         {
             ],
             "description": "Allows reflection of object attributes, including inherited and non-public ones",
             "homepage": "https://github.com/sebastianbergmann/object-reflector/",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/object-reflector/issues",
+                "source": "https://github.com/sebastianbergmann/object-reflector/tree/master"
+            },
             "time": "2017-03-29T09:07:27+00:00"
         },
         {
             ],
             "description": "Provides functionality to recursively process PHP variables",
             "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/recursion-context/issues",
+                "source": "https://github.com/sebastianbergmann/recursion-context/tree/master"
+            },
             "time": "2017-03-03T06:23:57+00:00"
         },
         {
             ],
             "description": "Provides a list of PHP built-in functions that operate on resources",
             "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
+                "source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
+            },
             "time": "2018-10-04T04:07:39+00:00"
         },
         {
             ],
             "description": "Library that helps with managing the version number of Git-hosted PHP projects",
             "homepage": "https://github.com/sebastianbergmann/version",
+            "support": {
+                "issues": "https://github.com/sebastianbergmann/version/issues",
+                "source": "https://github.com/sebastianbergmann/version/tree/master"
+            },
             "time": "2016-10-03T07:35:21+00:00"
         },
         {
             "name": "squizlabs/php_codesniffer",
-            "version": "3.5.5",
+            "version": "3.5.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
-                "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6"
+                "reference": "e97627871a7eab2f70e59166072a6b767d5834e0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
-                "reference": "73e2e7f57d958e7228fce50dc0c61f58f017f9f6",
+                "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/e97627871a7eab2f70e59166072a6b767d5834e0",
+                "reference": "e97627871a7eab2f70e59166072a6b767d5834e0",
                 "shasum": ""
             },
             "require": {
                 "phpcs",
                 "standards"
             ],
-            "time": "2020-04-17T01:09:41+00:00"
-        },
-        {
-            "name": "symfony/console",
-            "version": "v4.4.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/console.git",
-                "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/10bb3ee3c97308869d53b3e3d03f6ac23ff985f7",
-                "reference": "10bb3ee3c97308869d53b3e3d03f6ac23ff985f7",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "symfony/polyfill-mbstring": "~1.0",
-                "symfony/polyfill-php73": "^1.8",
-                "symfony/service-contracts": "^1.1|^2"
-            },
-            "conflict": {
-                "symfony/dependency-injection": "<3.4",
-                "symfony/event-dispatcher": "<4.3|>=5",
-                "symfony/lock": "<4.4",
-                "symfony/process": "<3.3"
+            "support": {
+                "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
+                "source": "https://github.com/squizlabs/PHP_CodeSniffer",
+                "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
             },
-            "provide": {
-                "psr/log-implementation": "1.0"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/config": "^3.4|^4.0|^5.0",
-                "symfony/dependency-injection": "^3.4|^4.0|^5.0",
-                "symfony/event-dispatcher": "^4.3",
-                "symfony/lock": "^4.4|^5.0",
-                "symfony/process": "^3.4|^4.0|^5.0",
-                "symfony/var-dumper": "^4.3|^5.0"
-            },
-            "suggest": {
-                "psr/log": "For using the console logger",
-                "symfony/event-dispatcher": "",
-                "symfony/lock": "",
-                "symfony/process": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Console\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Console Component",
-            "homepage": "https://symfony.com",
-            "time": "2020-03-30T11:41:10+00:00"
-        },
-        {
-            "name": "symfony/finder",
-            "version": "v4.4.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/finder.git",
-                "reference": "5729f943f9854c5781984ed4907bbb817735776b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/5729f943f9854c5781984ed4907bbb817735776b",
-                "reference": "5729f943f9854c5781984ed4907bbb817735776b",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "4.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Finder\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Finder Component",
-            "homepage": "https://symfony.com",
-            "time": "2020-03-27T16:54:36+00:00"
+            "time": "2020-08-10T04:50:15+00:00"
         },
         {
             "name": "symfony/polyfill-ctype",
-            "version": "v1.17.0",
+            "version": "v1.18.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9"
+                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
-                "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
+                "reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
                 "shasum": ""
             },
             "require": {
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.17-dev"
+                    "dev-master": "1.18-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
                 }
             },
             "autoload": {
                 "polyfill",
                 "portable"
             ],
-            "time": "2020-05-12T16:14:59+00:00"
-        },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.17.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "fa79b11539418b02fc5e1897267673ba2c19419c"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c",
-                "reference": "fa79b11539418b02fc5e1897267673ba2c19419c",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.17-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for the Mbstring extension",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "mbstring",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2020-05-12T16:47:27+00:00"
-        },
-        {
-            "name": "symfony/polyfill-php73",
-            "version": "v1.17.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-php73.git",
-                "reference": "a760d8964ff79ab9bf057613a5808284ec852ccc"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/a760d8964ff79ab9bf057613a5808284ec852ccc",
-                "reference": "a760d8964ff79ab9bf057613a5808284ec852ccc",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
+            "support": {
+                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.18.0"
             },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.17-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Php73\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ],
-                "classmap": [
-                    "Resources/stubs"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
+            "funding": [
                 {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
                 },
                 {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2020-05-12T16:47:27+00:00"
-        },
-        {
-            "name": "symfony/service-contracts",
-            "version": "v1.1.8",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/service-contracts.git",
-                "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf",
-                "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^7.1.3",
-                "psr/container": "^1.0"
-            },
-            "suggest": {
-                "symfony/service-implementation": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.1-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Contracts\\Service\\": ""
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
                 },
                 {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Generic abstractions related to writing services",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "abstractions",
-                "contracts",
-                "decoupling",
-                "interfaces",
-                "interoperability",
-                "standards"
-            ],
-            "time": "2019-10-14T12:27:06+00:00"
-        },
-        {
-            "name": "theseer/fdomdocument",
-            "version": "1.6.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/theseer/fDOMDocument.git",
-                "reference": "6e8203e40a32a9c770bcb62fe37e68b948da6dca"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/theseer/fDOMDocument/zipball/6e8203e40a32a9c770bcb62fe37e68b948da6dca",
-                "reference": "6e8203e40a32a9c770bcb62fe37e68b948da6dca",
-                "shasum": ""
-            },
-            "require": {
-                "ext-dom": "*",
-                "lib-libxml": "*",
-                "php": ">=5.3.3"
-            },
-            "type": "library",
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Arne Blankerts",
-                    "email": "arne@blankerts.de",
-                    "role": "lead"
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
                 }
             ],
-            "description": "The classes contained within this repository extend the standard DOM to use exceptions at all occasions of errors instead of PHP warnings or notices. They also add various custom methods and shortcuts for convenience and to simplify the usage of DOM.",
-            "homepage": "https://github.com/theseer/fDOMDocument",
-            "time": "2017-06-30T11:53:12+00:00"
+            "time": "2020-07-14T12:35:20+00:00"
         },
         {
             "name": "theseer/tokenizer",
                 }
             ],
             "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
+            "support": {
+                "issues": "https://github.com/theseer/tokenizer/issues",
+                "source": "https://github.com/theseer/tokenizer/tree/master"
+            },
             "time": "2019-06-13T22:48:21+00:00"
         },
         {
             "name": "webmozart/assert",
-            "version": "1.8.0",
+            "version": "1.9.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webmozart/assert.git",
-                "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6"
+                "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
-                "reference": "ab2cb0b3b559010b75981b1bdce728da3ee90ad6",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389",
+                "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.3.3 || ^7.0",
+                "php": "^5.3.3 || ^7.0 || ^8.0",
                 "symfony/polyfill-ctype": "^1.8"
             },
             "conflict": {
+                "phpstan/phpstan": "<0.12.20",
                 "vimeo/psalm": "<3.9.1"
             },
             "require-dev": {
                 "check",
                 "validate"
             ],
-            "time": "2020-04-18T12:12:48+00:00"
+            "support": {
+                "issues": "https://github.com/webmozart/assert/issues",
+                "source": "https://github.com/webmozart/assert/tree/master"
+            },
+            "time": "2020-07-08T17:02:28+00:00"
         }
     ],
     "aliases": [],
     "platform-dev": [],
     "platform-overrides": {
         "php": "7.1.29"
-    }
+    },
+    "plugin-api-version": "2.0.0"
 }
diff --git a/doc/md/3rd-party-libraries.md b/doc/md/3rd-party-libraries.md
deleted file mode 100644 (file)
index 7e7dd33..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-## CSS
-
-- Yahoo UI [CSS Reset](http://yuilibrary.com/yui/docs/cssreset/) - standardize cross-browser rendering
-
-## Javascript
-
-- [Awesomeplete](https://leaverou.github.io/awesomplete/) ([GitHub](https://github.com/LeaVerou/awesomplete)) - autocompletion in input forms
-- [bLazy](http://dinbror.dk/blazy/) ([GitHub](https://github.com/dinbror/blazy)) - lazy loading for thumbnails
-- [qr.js](http://neocotic.com/qr.js/) ([GitHub](https://github.com/neocotic/qr.js)) - QR code generation
-
-## PHP
-
-- [RainTPL](https://github.com/rainphp/raintpl) - HTML templating for PHP
-
-### Composer
-
-Library | Usage
----|---
-[`shaarli/netscape-bookmark-parser`](https://packagist.org/packages/shaarli/netscape-bookmark-parser) | Import bookmarks from Netscape files
-[`erusev/parsedown`](https://packagist.org/packages/erusev/parsedown) | Parse MarkDown syntax for the MarkDown plugin
-[`slim/slim`](https://packagist.org/packages/slim/slim) | Handle routes and middleware for the REST API
diff --git a/doc/md/Backup-and-restore.md b/doc/md/Backup-and-restore.md
new file mode 100644 (file)
index 0000000..e7e2775
--- /dev/null
@@ -0,0 +1,11 @@
+## Backup and restore
+
+All data and [configuration](Shaarli-configuration.md) is kept in the `data` directory. Backup this directory: 
+
+```bash
+rsync -avzP my.server.com:/var/www/shaarli.mydomain.org/data ~/backups/shaarli-data-$(date +%Y-%m-%d_%H%M)
+```
+
+It is strongly recommended to do periodic, automatic backups to a seperate machine. You can automate the command above using a cron job or full-featured backup solutions such as [rsnapshot](https://rsnapshot.org/)
+
+To restore a backup, simply put back the `data/` directory in place, owerwriting any existing files.
\ No newline at end of file
diff --git a/doc/md/Browsing-and-searching.md b/doc/md/Browsing-and-searching.md
deleted file mode 100644 (file)
index 16c6985..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-## Plain text search
-
-Use the `Search text` field to search in _any_ of the fields of all links (Title, URL, Description...)
-
-**Exclude text/tags:** Use the `-` operator before a word or tag (example `-uninteresting`) to prevent entries containing (or tagged) `uninteresting` from showing up in the search results.
-
-**Exact text search:** Use double-quotes (example `"exact search"`) to search for the exact expression.
-
-Both exclude patterns and exact searches can be combined with normal searches (example `"exact search" term otherterm -notthis "very exact" stuff -notagain`)
-
-## Tags search
-
-Use the `Filter by tags` field to restrict displayed links to entries tagged with one or multiple tags (use space to separate tags).  
-
-**Hidden tags:** Tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in.
-
-### Tag cloud
-
-The `Tag cloud` page diplays a "cloud" view of all tags in your Shaarli.
-
- * The most frequently used tags are displayed with a bigger font size.
- * When sorting by `Most used` or `Alphabetical`, tags are displayed as a _list_, along with counters and edit/delete buttons for each tag.
- * Clicking on any tag will display a list of all Shaares matching this tag.
- * Clicking on the counter next to a tag `example`, will filter the tag cloud to only display tags found in Shaares tagged `example`. Repeat this any number of times to further filter the tag cloud. Click `List all links with those tags` to display Shaares matching your current tag filter.
-
-## Filtering RSS feeds/Picture wall
-
-RSS feeds can also be restricted to only return items matching a text/tag search: see [RSS feeds](RSS-feeds).
-
-## Filter buttons
-
-Filter buttons can be found at the top left of the link list. They allow you to apply different filters to the list:
-
- * **Private links:** When this toggle button is enabled, only shaares set to `private` will be shown.
- * **Untagged links:** When the this toggle button is enabled (top left of the link list), only shaares _without any tags_ will be shown in the link list.
-Filter buttons are only available when logged in.
similarity index 74%
rename from doc/md/Community-&-Related-software.md
rename to doc/md/Community-and-related-software.md
index 54f18c8e36e416fb95be01cf3d7cedb33f289e7f..53a7555eab6f57c9e3fa26d19a74badc7cfd8678 100644 (file)
@@ -1,66 +1,87 @@
+# Community & related software
+
 _Unofficial but related work on Shaarli. If you maintain one of these,
 please get in touch with us to help us find a way to adapt your work to our fork._
 
-## Related software
 
+## Related software
 
 ### REST API clients
 See [REST API](REST-API) for a list of official and community clients.
 
 
 ### Third party plugins
-- [autosave](https://github.com/kalvn/shaarli-plugin-autosave) by [@kalvn](https://github.com/kalvn): Automatically saves data when editing a link to avoid any loss in case of crash or unexpected shutdown.
-- [Code Coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter.
-- [Disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli.
+
+- [autosave](https://github.com/kalvn/shaarli-plugin-autosave) by [@kalvn](https://github.com/kalvn): Automatically saves data when editing a Shaare to avoid any loss in case of crash or unexpected shutdown.
+- [code-coloration](https://github.com/ArthurHoaro/code-coloration) by [@ArthurHoaro](https://github.com/ArthurHoaro): client side code syntax highlighter.
+- [custom-css](https://github.com/immanuelfodor/shaarli-custom-css) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the look and feel of the UI with custom CSS rules
+- [disqus](https://github.com/kalvn/shaarli-plugin-disqus) by [@kalvn](https://github.com/kalvn): Adds Disqus comment system to your Shaarli.
+- [emojione](https://github.com/immanuelfodor/emojione) by [@immanuelfodor](https://github.com/immanuelfodor) - Resurrected fork of the original emojione project
+- [favicons](https://github.com/trailjeep/shaarli-favicons) by [@trailjeep](https://github.com/trailjeep) - Shaarli plugin to add favicon/filetype icons to Shaares.
 - [google analytics](https://github.com/ericjuden/Shaarli-Google-Analytics-Plugin) by [@ericjuden](http://github.com/ericjuden): Adds Google Analytics tracking support
 - [launch](https://github.com/ArthurHoaro/launch-plugin) - Launch Plugin is a plugin designed to enhance and customize Launch Theme for Shaarli.
-- [markdown-toolbar](https://github.com/immanuelfodor/shaarli-markdown-toolbar) by [@immanuelfodor](https://github.com/immanuelfodor) - Easily insert markdown syntax into the Description field when editing a link.
-- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related links based on the number of identical tags.
-- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks.
-- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your shared links from Shaarli
+- [markdown-toolbar](https://github.com/immanuelfodor/shaarli-markdown-toolbar) by [@immanuelfodor](https://github.com/immanuelfodor) - Easily insert markdown syntax into the Description field when editing a Shaare.
+- [related](https://github.com/ilesinge/shaarli-related) by [@ilesinge](https://github.com/ilesinge) - Show related Shaares based on the number of identical tags.
+- [shaarli-descriptor](https://github.com/immanuelfodor/shaarli-descriptor) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the default height/number of rows of the Description field when editing a Shaare.
 - [shaarli2mastodon](https://github.com/kalvn/shaarli2mastodon) by [@kalvn](https://github.com/kalvn) - This Shaarli plugin allows you to automatically publish links you post on your Mastodon timeline.
-- [shaarli-descriptor](https://github.com/immanuelfodor/shaarli-descriptor) by [@immanuelfodor](https://github.com/immanuelfodor) - Customize the default height/number of rows of the Description field when editing a link.
+- [shaarli2twitter](https://github.com/ArthurHoaro/shaarli2twitter) by [@ArthurHoaro](https://github.com/ArthurHoaro) - Automatically tweet your Shaares from Shaarli
+- [social](https://github.com/alexisju/social) by [@alexisju](https://github.com/alexisju): share links to social networks.
 - [urlextern](https://github.com/trailjeep/shaarli-urlextern) by [@trailjeep](https://github.com/trailjeep) - Shaarli plugin to open external links in a new tab/window.
-- [favicons](https://github.com/trailjeep/shaarli-favicons) by [@trailjeep](https://github.com/trailjeep) - Shaarli plugin to add favicon/filetype icons to links.
+- [webhooks](https://gitlab.com/flow.gunso/shaarli-webhooks) by [@flow.gunso](https://gitlab.com/flow.gunso) - Shaarli plugin that enables user-defined callback URL, i.e. webhooks, for specific Shaarli events (link saving, deletion...)
+
 
 ### Third-party themes
+
 See [Theming](Theming) for a list of community-contributed themes, and an installation guide.
 
 
 ### Integration with other platforms 
+
 - [tt-rss-shaarli](https://github.com/jcsaaddupuy/tt-rss-shaarli) - [Tiny-Tiny RSS](http://tt-rss.org/) plugin that adds support for sharing articles with Shaarli
-- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli links on the sidebar
+- [octopress-shaarli](https://github.com/ahmet2mir/octopress-shaarli) - Octopress plugin to retrieve Shaarli Shaares on the sidebar
 - [Scuttle to Shaarli](https://github.com/q2apro/scuttle-to-shaarli) - Import bookmarks from Scuttle
 - [Shaarli app for Cloudron](https://git.cloudron.io/cloudron/shaarli-app) - Effortlessly run Shaarli with the help of [Cloudron](https://cloudron.io/) [![Install](https://cloudron.io/img/button.svg)](https://cloudron.io/button.html?app=com.github.shaarli)
 - [Shaarli_ynh](https://github.com/YunoHost-Apps/shaarli_ynh) - Shaarli is available as a [Yunohost](https://yunohost.org) app [![Install Shaarli with YunoHost](https://install-app.yunohost.org/install-with-yunohost.png)](https://install-app.yunohost.org/?app=shaarli)
 - [pelican](https://blog.getpelican.com) static blog generator plugin to auto-post articles on a Shaarli instance: [shaarli_poster](https://github.com/getpelican/pelican-plugins/tree/master/shaarli_poster)
 
+
 ### Mobile Apps
+
 - [ShaarliOS](https://github.com/mro/ShaarliOS) - Apple iOS share extension.
 - [Shaarli for Android](http://sebsauvage.net/links/?ZAyDzg) - Android application that adds Shaarli as a sharing provider
-- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add links directly into your Shaarli
+- [Shaarlier for Android](https://github.com/dimtion/Shaarlier) - Android application to simply add Shaares directly into your Shaarli
 - [Stakali for Android](https://stakali.toneiv.eu) - Stakali is a personal bookmark manager which synchronizes with Shaarli 
 
+
 ### Desktop Apps
+
 - [Ulauncher Extension](https://github.com/sebw/ulauncher-shaarli) - Ulauncher is an an application launcher for Linux, this extension allows research in your Shaarli
 
+
 ### Browser addons
+
 - [Shaarli Firefox Extension](https://github.com/ikipatang/shaarli-web-extension) - toolbar button to share your current tab with Shaarli.
 - [Shaarli Chrome Extension](https://github.com/octplane/Shiny-Shaarli) - toolbar button to share your current tab with Shaarli.
 
+
 ### Server apps
+
 - [shaarchiver](https://github.com/nodiscc/shaarchiver) - Archive your Shaarli bookmarks and their content
 - [shaarli-river](https://github.com/mknexen/shaarli-river) - An aggregator for shaarlis with many features 
-- [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features (a very popular running instance among French shaarliers: [shaarli.fr](http://shaarli.fr/))
+- [Shaarlo](https://github.com/DMeloni/shaarlo) - An aggregator for shaarlis with many features
 - [Shaarlimages](https://github.com/BoboTiG/shaarlimages) - An image-oriented aggregator for Shaarlis
 - [mknexen/shaarli-api](https://github.com/mknexen/shaarli-api) - A REST API for Shaarli
 - [Self dead link](https://framagit.org/qwertygc/shaarli-dev-code/blob/master/self-dead-link.php) - Detect dead links on shaarli. This version use the database of shaarli. [Another version](https://framagit.org/qwertygc/shaarli-dev-code/blob/master/dead-link.php), can be used for other shaarli instances (but is more resource consuming).
 - [Bookmark Archiver](https://github.com/pirate/bookmark-archiver) - Save an archived copy of all websites starred using browser bookmarks/Shaarli/Delicious/Instapaper/Unmark.it/Pocket/Pinboard. Outputs browseable html. 
 
+
 ## Alternatives to Shaarli
+
 See [awesome-selfhosted: bookmarks & link sharing](https://github.com/Kickball/awesome-selfhosted/#bookmarks--link-sharing).
 
+
 ## Community
+
 - [Liens en vrac de sebsauvage](http://sebsauvage.net/links/) - the original Shaarli
 - [A large list of Shaarlis](http://porneia.free.fr/pub/links/ou-est-shaarli.html)
 - [A list of working Shaarli aggregators](https://raw.githubusercontent.com/Oros42/find_shaarlis/master/annuaires.json)
@@ -71,8 +92,17 @@ See [awesome-selfhosted: bookmarks & link sharing](https://github.com/Kickball/a
 - [Original revisions history](http://sebsauvage.net/wiki/doku.php?id=php:shaarli:history)
 - [Shaarli.fr/my](https://www.shaarli.fr/my.php) - Unofficial, unsupported (old fork) hosted Shaarlis provider, courtesy of [DMeloni](https://github.com/DMeloni)
 
+
 ### Articles and social media discussions
-- 2016-09-22 - Hacker News - https://news.ycombinator.com/item?id=12552176
+- 2020-04-05 - Hacker News - [Self-hosted instance of Shaarli - it is simple, fast and reliable](https://news.ycombinator.com/item?id=22780219)
+- 2016-10-10 - Framasoft - [MyFrama : vos favoris partout, avec vous, rien qu’à vous !](https://framablog.org/2016/10/10/myframa-vos-favoris-et-framasofteries-partout-avec-vous-rien-qua-vous/)
+- 2016-09-22 - Hacker News - [Shaarli – Personal, minimalist, database-free, bookmarking service (github.com)](https://news.ycombinator.com/item?id=12552176)
 - 2015-08-15 - Reddit - [Question about migrating from WordPress to Shaarli.](https://www.reddit.com/r/selfhosted/comments/3h3zwh/question_about_migrating_from_wordpress_to_shaarli/)
-- 2015-06-22 - Hacker News - https://news.ycombinator.com/item?id=9755366
+- 2015-06-22 - Hacker News - [Shaarli: Self-hosted del.icio.us alternative (sebsauvage.net)](https://news.ycombinator.com/item?id=9755366)
 - 2015-05-12 - Reddit - [shaarli - Self hosted Bookmarking / Delicious (PHP, MySQL)](https://www.reddit.com/r/selfhosted/comments/35pkkc/shaarli_self_hosted_bookmarking_delicious_php/)
+- 2014-10-15 - OpenSource.com - [Five open source alternatives to popular web apps](https://opensource.com/life/14/10/five-open-source-alternatives-popular-web-apps)
+
+It also appears in the following recommendation lists:
+- [AlternativeTo](https://alternativeto.net/software/shaarli/)
+- [FramaLibre](https://framalibre.org/content/shaarli)
+- [Project Awesome: Selfhosted Bookmarks and Link Sharing](https://project-awesome.org/Kickball/awesome-selfhosted)
diff --git a/doc/md/Continuous-integration-tools.md b/doc/md/Continuous-integration-tools.md
deleted file mode 100644 (file)
index f7819d5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-## Local development
-A [`Makefile`](https://github.com/shaarli/Shaarli/blob/master/Makefile) is available to perform project-related operations:
-
-- Documentation - generate a local HTML copy of the GitHub wiki
-- [Static analysis](Static-analysis) - check that the code is compliant to PHP conventions
-- [Unit tests](Unit-tests) - ensure there are no regressions introduced by new commits
-
-## Automatic builds
-[Travis CI](http://docs.travis-ci.com/) is a Continuous Integration build server, that runs a build:
-
-- each time a commit is merged to the mainline (`master` branch)
-- each time a Pull Request is submitted or updated
-
-A build is composed of several jobs: one for each supported PHP version (see [Server requirements](Server requirements)).
-
-Each build job:
-
-- updates Composer
-- installs 3rd-party test dependencies with Composer
-- runs [Unit tests](Unit-tests)
-- runs ESLint check
-
-After all jobs have finished, Travis returns the results to GitHub:
-
-- a status icon represents the result for the `master` branch: [![](https://api.travis-ci.org/shaarli/Shaarli.svg)](https://travis-ci.org/shaarli/Shaarli)
-- Pull Requests are updated with the Travis result
-    - Green: all tests have passed
-    - Red: some tests failed
-    - Orange: tests are pending
-
-## Documentation
-[mkdocs](https://www.mkdocs.org/) is used to convert markdown documentation to HTML pages. The [public documentation](https://shaarli.readthedocs.io/en/master/) website is rendered and hosted by [readthedocs.org](https://readthedocs.org/). A copy of the documentation is also included in prebuilt [release archives](https://github.com/shaarli/Shaarli/releases) (`doc/html/` path in your Shaarli installation). To generate the HTML documentation locally, install a recent version of Python `setuptools` and run    `make doc`.
diff --git a/doc/md/Development-guidelines.md b/doc/md/Development-guidelines.md
deleted file mode 100644 (file)
index 46b7c6f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-## Development guidelines
-
-Please have a look at the following pages:
-
-- [Contributing to Shaarli](https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md)
-- [Static analysis](Static-analysis) - patches should try to stick to the 
-[PHP Standard Recommendations](http://www.php-fig.org/psr/) (PSR), especially:
-    - [PSR-1](http://www.php-fig.org/psr/psr-1/) - Basic Coding Standard
-    - [PSR-2](http://www.php-fig.org/psr/psr-2/) - Coding Style Guide
-- [Unit tests](Unit-tests)
-- Javascript linting - Shaarli uses [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript). 
-Run `make eslint` to check JS style.
-- [GnuPG signature](GnuPG-signature) for tags/releases
diff --git a/doc/md/Directory-structure.md b/doc/md/Directory-structure.md
deleted file mode 100644 (file)
index c0b4939..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-## Directory structure
-
-Here is the directory structure of Shaarli and the purpose of the different files:
-
-```bash
-       index.php        # Main program
-       application/     # Shaarli classes
-               ├── LinkDB.php
-
-        ...
-
-               └── Utils.php
-       tests/           # Shaarli unitary & functional tests
-               ├── LinkDBTest.php
-
-        ...
-
-               ├── utils    # utilities to ease testing
-               │   └── ReferenceLinkDB.php
-               └── UtilsTest.php
-       assets/
-           ├── common/                # Assets shared by multiple themes
-               ├── ...
-        ├── default/               # Assets for the default template, before compilation
-            ├── fonts/                  # Font files
-            ├── img/                    # Images used by the default theme
-            ├── js/                     # JavaScript files in ES6 syntax
-            ├── scss/                   # SASS files
-        └── vintage/               # Assets for the vintage template, before compilation
-            └── ...
-    COPYING          # Shaarli license
-    inc/             # static assets and 3rd party libraries
-        └── rain.tpl.class.php     # RainTPL templating library
-    images/          # Images and icons used in Shaarli
-    data/            # data storage: bookmark database, configuration, logs, banlist...
-        ├── config.json.php        # Shaarli configuration (login, password, timezone, title...)
-        ├── datastore.php          # Your link database (compressed).
-        ├── ipban.php              # IP address ban system data
-        ├── lastupdatecheck.txt    # Update check timestamp file
-        └── log.txt                # login/IPban log.
-    tpl/             # RainTPL templates for Shaarli. They are used to build the pages.
-        ├── default/               # Default Shaarli theme
-            ├── fonts/                  # Font files
-            ├── img/                    # Images
-            ├── js/                     # JavaScript files compiled by Babel and compatible with all browsers
-            ├── css/                    # CSS files compiled with SASS
-        └── vintage/               # Legacy Shaarli theme
-            └── ...
-    cache/           # thumbnails cache
-                     # This directory is automatically created. You can erase it anytime you want.
-    tmp/             # Temporary directory for compiled RainTPL templates.
-                     # This directory is automatically created. You can erase it anytime you want.
-    vendor/          # Third-party dependencies. This directory is created by Composer
-```
diff --git a/doc/md/Docker.md b/doc/md/Docker.md
new file mode 100644 (file)
index 0000000..c152fe9
--- /dev/null
@@ -0,0 +1,227 @@
+# Docker
+
+[Docker](https://docs.docker.com/get-started/overview/) is an open platform for developing, shipping, and running applications
+
+## Install Docker
+
+Install [Docker](https://docs.docker.com/engine/install/), by following the instructions relevant to your OS / distribution, and start the service. For example on [Debian](https://docs.docker.com/engine/install/debian/):
+
+```bash
+# update your package lists
+sudo apt update
+# remove old versions
+sudo apt-get remove docker docker-engine docker.io containerd runc
+# install requirements
+sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
+# add docker's GPG signing key
+curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
+# add the repository
+sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
+# install docker engine
+sudo apt-get update
+sudo apt-get install docker-ce docker-ce-cli containerd.io
+# Start and enable Docker service
+sudo systemctl enable docker && sudo systemctl start docker
+# verify that Docker is properly configured
+sudo docker run hello-world
+```
+
+In order to run Docker commands as a non-root user, you must add the `docker` group to this user:
+
+```bash
+# Add docker group as secondary group
+sudo usermod -aG docker your-user
+# Reboot or logout
+# Then verify that Docker is properly configured, as "your-user"
+docker run hello-world
+```
+
+## Get and run a Shaarli image
+
+Shaarli images are available on [DockerHub](https://hub.docker.com/r/shaarli/shaarli/) `shaarli/shaarli`:
+
+- `latest`: latest branch (last release)
+- `stable`: stable branch (last release in previous major version)
+- `master`: master branch (development branch)
+
+These images are built automatically on DockerHub and rely on:
+
+- [Alpine Linux](https://www.alpinelinux.org/)
+- [PHP7-FPM](http://php-fpm.org/)
+- [Nginx](http://nginx.org/)
+
+Additional Dockerfiles are provided for the `arm32v7` platform, relying on [Linuxserver.io Alpine armhf images](https://hub.docker.com/r/lsiobase/alpine.armhf/). These images must be built using [`docker build`](https://docs.docker.com/engine/reference/commandline/build/) on an `arm32v7` machine or using an emulator such as [qemu](https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/).
+
+Here is an example of how to run Shaarli latest image using Docker:
+
+```bash
+# download the 'latest' image from dockerhub
+docker pull shaarli/shaarli
+
+# create persistent data volumes/directories on the host
+docker volume create shaarli-data
+docker volume create shaarli-cache
+
+# create a new container using the Shaarli image
+# --detach: run the container in background
+# --name: name of the created container/instance
+# --publish: map the host's :8000 port to the container's :80 port
+# --rm: automatically remove the container when it exits
+# --volume: mount persistent volumes in the container ($volume_name:$volume_mountpoint)
+docker run --detach \
+           --name myshaarli \
+           --publish 8000:80 \
+           --rm \
+           --volume shaarli-data:/var/www/shaarli/data \
+           --volume shaarli-cache:/var/www/shaarli/cache \
+           shaarli/shaarli:latest
+
+# verify that the container is running
+docker ps | grep myshaarli
+
+# to completely remove the container
+docker stop myshaarli # stop the running container
+docker ps | grep myshaarli # verify the container is no longer running
+docker ps -a | grep myshaarli # verify the container is stopped
+docker rm myshaarli # destroy the container
+docker ps -a | grep myshaarli # verify th container has been destroyed
+
+```
+
+After running `docker run` command, your Shaarli instance should be available on the host machine at [localhost:8000](http://localhost:8000). In order to access your instance through a reverse proxy, we recommend using our [Docker Compose](#docker-compose) build.
+
+## Docker Compose
+
+A [Compose file](https://docs.docker.com/compose/compose-file/) is a common format for defining and running multi-container Docker applications.
+
+A `docker-compose.yml` file can be used to run a persistent/autostarted shaarli service using [Docker Compose](https://docs.docker.com/compose/) or in a [Docker stack](https://docs.docker.com/engine/reference/commandline/stack_deploy/).
+
+Shaarli provides configuration file for Docker Compose, that will setup a Shaarli instance, a [Træfik](https://containo.us/traefik/) instance (reverse proxy) with [Let's Encrypt](https://letsencrypt.org/) certificates, a Docker network, and volumes for Shaarli data and Træfik TLS configuration and certificates.
+
+Download docker-compose from the [release page](https://docs.docker.com/compose/install/):
+
+```bash
+$ sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
+$ sudo chmod +x /usr/local/bin/docker-compose
+```
+
+To run Shaarli container and its reverse proxy, you can execute the following commands:
+
+```bash
+# create a new directory to store the configuration:
+$ mkdir shaarli && cd shaarli
+# Download the latest version of Shaarli's docker-compose.yml
+$ curl -L https://raw.githubusercontent.com/shaarli/Shaarli/latest/docker-compose.yml -o docker-compose.yml
+# Create the .env file and fill in your VPS and domain information
+# (replace <MY_SHAARLI_DOMAIN> and <MY_CONTACT_EMAIL> with your actual information)
+$ echo 'SHAARLI_VIRTUAL_HOST=shaarli.mydomain.org' > .env
+$ echo 'SHAARLI_LETSENCRYPT_EMAIL=admin@mydomain.org' >> .env
+# Pull the Docker images
+$ docker-compose pull
+# Run!
+$ docker-compose up -d
+```
+
+After a few seconds, you should be able to access your Shaarli instance at [https://shaarli.mydomain.org](https://shaarli.mydomain.org) (replace your own domain name).
+
+## Running dockerized Shaarli as a systemd service
+
+It is possible to start a dockerized Shaarli instance as a systemd service (systemd is the service management tool on several distributions). After installing Docker, use the following steps to run your shaarli container Shaarli to run on system start.
+
+As root, create `/etc/systemd/system/docker.shaarli.service`:
+
+```ini
+[Unit]
+Description=Shaarli Bookmark Manager Container
+After=docker.service
+Requires=docker.service
+
+
+[Service]
+Restart=always
+
+# Put any environment you want in an included file, like $host- or $domainname in this example
+EnvironmentFile=/etc/sysconfig/box-environment
+
+# It's just an example..
+ExecStart=/usr/bin/docker run \
+  -p 28010:80 \
+  --name ${hostname}-shaarli \
+  --hostname shaarli.${domainname} \
+  -v /srv/docker-volumes-local/shaarli-data:/var/www/shaarli/data:rw \
+  -v /etc/localtime:/etc/localtime:ro \
+  shaarli/shaarli:latest
+
+ExecStop=/usr/bin/docker rm -f ${hostname}-shaarli
+
+[Install]
+WantedBy=multi-user.target
+```
+
+```bash
+# reload systemd services definitions
+systemctl daemon-reload
+# start the servie and enable it a boot time
+systemctl enable docker.shaarli.service --now
+# verify that the service is running
+systemctl status docker.*
+# inspect system log if needed
+journalctl -f
+```
+
+
+
+## Docker cheatsheet
+
+```bash
+# pull/update an image
+$ docker pull shaarli/shaarli:release
+# run a container from an image
+$ docker run shaarli/shaarli:latest
+# list available images
+$ docker images ls
+# list running containers
+$ docker ps
+# list running AND stopped containers
+$ docker ps -a
+# run a command in a running container
+$ docker exec -ti <container-name-or-first-letters-of-id> bash
+# follow logs of a running container
+$ docker logs -f <container-name-or-first-letters-of-id>
+# delete unused images to free up disk space
+$ docker system prune --images
+# delete unused volumes to free up disk space (CAUTION all data in unused volumes will be lost)
+$ docker system prunt --volumes
+# delete unused containers
+$ docker system prune
+```
+
+
+## References
+
+- [Docker: using volumes](https://docs.docker.com/storage/volumes/)
+- [Dockerfile best practices](https://docs.docker.com/articles/dockerfile_best-practices/)
+- [Dockerfile reference](https://docs.docker.com/reference/builder/)
+- [DockerHub: GitHub automated build](https://docs.docker.com/docker-hub/github/)
+- [DockerHub: Repositories](https://docs.docker.com/userguide/dockerrepos/)
+- [DockerHub: Teams and organizations](https://docs.docker.com/docker-hub/orgs/)
+- [Get Docker CE for Debian](https://docs.docker.com/install/linux/docker-ce/debian/)
+- [Install Docker Compose](https://docs.docker.com/compose/install/)
+- [Interactive Docker training portal](https://www.katacoda.com/courses/docker/) on [Katakoda](https://www.katacoda.com/)
+- [Service management: Nginx in the foreground](http://nginx.org/en/docs/ngx_core_module.html#daemon)
+- [Service management: Using supervisord](https://docs.docker.com/articles/using_supervisord/)
+- [Volumes](https://docs.docker.com/storage/volumes/)
+- [Volumes](https://docs.docker.com/userguide/dockervolumes/)
+- [Where are Docker images stored?](http://blog.thoward37.me/articles/where-are-docker-images-stored/)
+- [docker create](https://docs.docker.com/engine/reference/commandline/create/)
+- [Docker Documentation](https://docs.docker.com/)
+- [docker exec](https://docs.docker.com/engine/reference/commandline/exec/)
+- [docker images](https://docs.docker.com/engine/reference/commandline/images/)
+- [docker logs](https://docs.docker.com/engine/reference/commandline/logs/)
+- [docker logs](https://docs.docker.com/engine/reference/commandline/logs/)
+- [Docker Overview](https://docs.docker.com/engine/docker-overview/)
+- [docker ps](https://docs.docker.com/engine/reference/commandline/ps/)
+- [docker pull](https://docs.docker.com/engine/reference/commandline/pull/)
+- [docker run](https://docs.docker.com/engine/reference/commandline/run/)
+- [docker-compose logs](https://docs.docker.com/compose/reference/logs/)
+- Træfik: [Getting Started](https://docs.traefik.io/), [Docker backend](https://docs.traefik.io/configuration/backends/docker/), [Let's Encrypt](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/), [Docker image](https://hub.docker.com/_/traefik/)
\ No newline at end of file
diff --git a/doc/md/Download-and-Installation.md b/doc/md/Download-and-Installation.md
deleted file mode 100644 (file)
index ec68762..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-To install Shaarli, simply place the files in a directory under your webserver's
-Document Root (or directly at the document root).
-
-Also, please make sure your server is properly [configured](Server-configuration.md).
-
-Multiple releases branches are available:
-
-- latest (last release)
-- stable (previous major release)
-- master (development)
-
-Using one of the following methods:
-
-- by downloading full release archives including all dependencies
-- by downloading Github archives
-- by cloning the Git repository
-- using Docker: [see the documentation](docker/shaarli-images.md)
-
---------------------------------------------------------------------------------
-
-## Latest release (recommended)
-
-### Download as an archive
-
-In most cases, you should download the latest Shaarli release from the [releases](https://github.com/shaarli/Shaarli/releases) page. Download our **shaarli-full** archive to include dependencies.
-
-The current latest released version is `v0.10.4`
-
-```bash
-$ wget https://github.com/shaarli/Shaarli/releases/download/v0.10.4/shaarli-v0.10.4-full.zip
-$ unzip shaarli-v0.10.4-full.zip
-$ mv Shaarli /path/to/shaarli/
-```
-
-### Using git
-
-Cloning using `git` or downloading Github branches as zip files requires additional steps:
-
- * Install [Composer](Unit-tests.md#install_composer) to manage third-party [PHP dependencies](3rd-party-libraries.md#composer).
- * Install [yarn](https://yarnpkg.com/lang/en/docs/install/) to build the frontend dependencies.
- * Install [python3-virtualenv](https://pypi.python.org/pypi/virtualenv) to build the local HTML documentation.
-
-```
-$ mkdir -p /path/to/shaarli && cd /path/to/shaarli/
-$ git clone -b latest https://github.com/shaarli/Shaarli.git .
-$ composer install --no-dev --prefer-dist
-$ make build_frontend
-$ make translate
-$ make htmldoc
-```
-
---------------------------------------------------------------------------------
-
-## Stable version
-
-The stable version has been experienced by Shaarli users, and will receive security updates.
-
-
-### Download as an archive
-
-As a .zip archive:
-
-```bash
-$ wget https://github.com/shaarli/Shaarli/archive/stable.zip
-$ unzip stable.zip
-$ mv Shaarli-stable /path/to/shaarli/
-```
-
-As a .tar.gz archive :
-
-```bash
-$ wget https://github.com/shaarli/Shaarli/archive/stable.tar.gz
-$ tar xvf stable.tar.gz
-$ mv Shaarli-stable /path/to/shaarli/
-```
-
-### Using git
-
-Install [Composer](Unit-tests.md#install_composer) to manage Shaarli dependencies.
-
-```bash
-$ git clone https://github.com/shaarli/Shaarli.git -b stable /path/to/shaarli/
-# install/update third-party dependencies
-$ cd /path/to/shaarli/
-$ composer install --no-dev --prefer-dist
-```
-
-
---------------------------------------------------------------------------------
-
-## Development version (mainline)
-
-_Use at your own risk!_
-
-Install [Composer](Unit-tests.md#install_composer) to manage Shaarli PHP dependencies,
-and [yarn](https://yarnpkg.com/lang/en/docs/install/)
-for front-end dependencies.
-
-To get the latest changes from the `master` branch:
-
-```bash
-# clone the repository
-$ git clone https://github.com/shaarli/Shaarli.git -b master /path/to/shaarli/
-# install/update third-party dependencies
-$ cd /path/to/shaarli
-$ composer install --no-dev --prefer-dist
-$ make build_frontend
-$ make translate
-$ make htmldoc
-```
-
--------------------------------------------------------------------------------
-
-## Finish Installation
-
-Once Shaarli is downloaded and files have been placed at the correct location, open it this location your favorite browser.
-
-![install screenshot](images/install-shaarli.png)
-
-Setup your Shaarli installation, and it's ready to use!
-
-## Updating Shaarli
-
-See [Upgrade and Migration](Upgrade-and-migration)
diff --git a/doc/md/FAQ.md b/doc/md/FAQ.md
deleted file mode 100644 (file)
index a2ec7d5..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-### Why did you create Shaarli ?
-
-I was a StumbleUpon user. Then I got fed up with they big toolbar. I switched to delicious, which was lighter, faster and more beautiful. Until Yahoo bought it. Then the export API broke all the time, delicious became slow and was ditched by Yahoo. I switched to Diigo, which is not bad, but does too much. And Diigo is sslllooooowww and their Firefox extension a bit buggy. And… oh… **their Firefox addon sends to Diigo every single URL you visit** (Don't believe me ? Use [Tamper Data](https://addons.mozilla.org/en-US/firefox/addon/tamper-data/) and open any page).
-
-Enough is enough. Saving simple links should not be a complicated heavy thing. I ditched them all and wrote my own: Shaarli. It's simple, but it does the job and does it well. And my data is not hosted on a foreign server, but on my server.
-
-### Why use Shaarli and not Delicious/Diigo ?
-
-With Shaarli:
-
-- The data is yours: It's hosted on your server.
-- Never fear of having your data locked-in.
-- Never fear to have your data sold to third party.
-- Your private links are not hosted on a third party server.
-- You are not tracked by browser addons (like Diigo does)
-- You can change the look and feel of the pages if you want.
-- You can change the behaviour of the program.
-- It's magnitude faster than most bookmarking services.
-
-### What does Shaarli mean?
-
-Shaarli stands for _shaaring_ your _links_.
-
-### My Shaarli is broken!
-First of all, ensure that both the [web server](Server-configuration) and
-[Shaarli](Shaarli-configuration) are correctly configured, and that your
-installation is [supported](Server-configuration).
-
-If everything looks right but the issue(s) remain(s), please:
-
-- take a look at the [troubleshooting](Troubleshooting) section
-- come [chat with us](https://gitter.im/shaarli/Shaarli) on Gitter, we'll be happy to help ;-)
-- browse active [issues](https://github.com/shaarli/Shaarli/issues) and [Pull Requests](https://github.com/shaarli/Shaarli/pulls)
-    - if you find one that is related to the issue, feel free to comment and provide additional details (host/Shaarli setup)
-    - else, [open a new issue](https://github.com/shaarli/Shaarli/issues/new), and provide information about the problem:
-        - _what happens?_ - display glitches, invalid data, security flaws...
-        - _what is your configuration?_  - OS, server version, activated extensions, web browser...
-        - _is it reproducible?_
-
-### Why not use a real database? Files are slow!
-
-Does browsing [this page](http://sebsauvage.net/links/) feel slow? Try browsing older pages, too.
-
-It's not slow at all, is it? And don't forget the database contains more than 16000 links, and it's on a shared host, with 32000 visitors/day for my website alone. And it's still damn fast. Why?
-
-The data file is only 3.7 Mb. It's read 99% of the time, and is probably already in the operation system disk cache. So generating a page involves no I/O at all most of the time.
diff --git a/doc/md/Installation.md b/doc/md/Installation.md
new file mode 100644 (file)
index 0000000..11b5da8
--- /dev/null
@@ -0,0 +1,78 @@
+# Installation
+
+Once your server is [configured](Server-configuration.md), install Shaarli:
+
+## From release ZIP
+
+To install Shaarli, simply place the files from the latest [release .zip archive](https://github.com/shaarli/Shaarli/releases) under your webserver's document root (directly at the document root, or in a subdirectory). Download the **shaarli-vX.X.X-full** archive to include dependencies.
+
+```bash
+wget https://github.com/shaarli/Shaarli/releases/download/v0.11.1/shaarli-v0.11.1-full.zip
+unzip shaarli-v0.11.1-full.zip
+sudo rsync -avP Shaarli/ /var/www/shaarli.mydomain.org/
+```
+
+## From sources
+
+These components are required to build Shaarli:
+
+- [Composer](dev/Development.md#install-composer) to manage third-party [PHP dependencies](dev/Development#third-party-libraries).
+- [yarn](https://yarnpkg.com/lang/en/docs/install/) to build frontend dependencies.
+- [python3-virtualenv](https://pypi.python.org/pypi/virtualenv) to build local HTML documentation.
+
+Clone the repository, either pointing to:
+
+- any [tagged release](https://github.com/shaarli/Shaarli/releases)
+- `latest`: the latest tagged release
+- `master`: development branch
+
+```bash
+# clone the branch/tag of your choice
+$ git clone -b latest https://github.com/shaarli/Shaarli.git /home/me/Shaarli
+# OR download/extract the tar.gz/zip: wget https://github.com/shaarli/Shaarli/archive/latest.tar.gz...
+
+# enter the directory
+$ cd /home/me/Shaarli
+# install 3rd-party PHP dependencies
+$ composer install --no-dev --prefer-dist
+# build frontend static assets
+$ make build_frontend
+# build translations
+$ make translate
+# build HTML documentation
+$ make htmldoc
+# copy the resulting shaarli directory under your webserver's document root
+$ rsync -avP /home/me/Shaarli/ /var/www/shaarli.mydomain.org/
+```
+
+## Set file permissions
+
+Regardless of the installation method, appropriate [file permissions](dev/Development.md#directory-structure) must be set:
+
+```bash
+sudo chown -R root:www-data /var/www/shaarli.mydomain.org
+sudo chmod -R g+rX /var/www/shaarli.mydomain.org
+sudo chmod -R g+rwX /var/www/shaarli.mydomain.org/{cache/,data/,pagecache/,tmp/}
+```
+
+## Using Docker
+
+[See the documentation](Docker.md)
+
+
+## Finish Installation
+
+Once Shaarli is downloaded and files have been placed at the correct location, open this location your web browser.
+
+Enter basic settings for your Shaarli installation, and it's ready to use!
+
+![](images/07-installation.jpg)
+
+Congratulations! Your Shaarli is now available at `https://shaarli.mydomain.org`.
+
+You can further [configure Shaarli](Shaarli-configuration.md), setup [Plugins](Plugins.md) or [additional software](Community-and-related-software.md).
+
+
+## Upgrading Shaarli
+
+See [Upgrade and Migration](Upgrade-and-migration)
diff --git a/doc/md/Link-structure.md b/doc/md/Link-structure.md
deleted file mode 100644 (file)
index 0a2d0f8..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-## Link structure
-
-Every link available through the `LinkDB` object is represented as an array 
-containing the following fields:
-
-  * `id` (integer): Unique identifier.
-  * `title` (string): Title of the link.
-  * `url` (string): URL of the link. Used for displayable links (without redirector, url encoding, etc.).  
-           Can be absolute or relative for Notes.
-  * `real_url` (string): Real destination URL, can be redirected, encoded, etc.
-  * `shorturl` (string): Permalink small hash.
-  * `description` (string): Link text description.
-  * `private` (boolean): whether the link is private or not.
-  * `tags` (string): all link tags separated by a single space
-  * `thumbnail` (string|boolean): relative path of the thumbnail cache file, or false if there isn't any.
-  * `created` (DateTime): link creation date time.
-  * `updated` (DateTime): last modification date time.
-  
\ No newline at end of file
index 3e261815252ac38473dace088a6c40fa7574d573..a9f5f1a84e0bf8f248ae18c438cfde98d649935c 100644 (file)
@@ -1,14 +1,13 @@
-## Plugin installation
+# Plugins
 
-There is a bunch of plugins shipped with Shaarli, where there is nothing to do to install them.
+## Installation
 
-If you want to install a third party plugin:
+For plugins shipped with Shaarli, no installation is required.
 
-- Download it.
-- Put it in the `plugins` directory in Shaarli's installation folder.
-- Make sure you put it correctly:
+If you want to install a third party plugin, download it to the `plugins` directory in Shaarli's installation folder:
 
-```
+```bash
+# example directory structure
 | index.php
 | plugins/
 |---| custom_plugin/
@@ -17,63 +16,47 @@ If you want to install a third party plugin:
 
 ```
 
-  * Make sure your webserver can read and write the files in your plugin folder.
+Make sure your webserver can read and write the files in your plugin folder.
 
-## Plugin configuration
 
-In Shaarli's administration page (`Tools` link), go to `Plugin administration`.
+## Configuration
 
-Here you can enable and disable all plugins available, and configure them.
+From Shaarli's administration page (`Tools` link), go to `Plugin administration`. Here you can enable and disable all plugins available, and configure them.
 
 ![administration screenshot](https://camo.githubusercontent.com/5da68e191969007492ca0fbeb25f3b2357b748cc/687474703a2f2f692e696d6775722e636f6d2f766837544643712e706e67)
 
-## Plugin order
+
+## Order
 
 In the plugin administration page, you can move enabled plugins to the top or bottom of the list. The first plugins in the list will be processed first.
 
-This is important in case plugins are depending on each other. Read plugins README details for more information.
+This is important in case plugins depend on each other. Read plugins READMEs for more information.
 
 **Use case**: The (non existent) plugin `shaares_footer` adds a footer to every shaare in Markdown syntax. It needs to be processed *before* (higher in the list) the Markdown plugin. Otherwise its syntax won't be translated in HTML.
 
-## File mode
 
-Enabled plugin are stored in your `config.json.php` parameters file, under the `array`:
+## Configuration file
 
-```php
-$GLOBALS['config']['ENABLED_PLUGINS']
-```
+Enabled plugins are stored in your [Configuration file](Shaarli-configuration).
 
-You can edit them manually here.
-Example:
+## Usage
 
-```php
-$GLOBALS['config']['ENABLED_PLUGINS'] = array(
-    'qrcode',
-    'archiveorg',
-    'wallabag',
-    'markdown',
-);
-```
-
-### Plugin usage
-
-#### Official plugins
+### Official plugins
 
 Usage of each plugin is documented in it's README file:
 
- * `addlink-toolbar`: Adds the addlink input on the linklist page
- * `archiveorg`: For each link, add an Archive.org icon
+ * `addlink-toolbar`: Adds the addlink input on the Shaares list page
+ * `archiveorg`: For each Shaare, add a link to the archived page on Archive.org
  * `default_colors`: Override default theme colors.
  * `isso`: Let visitor comment your shaares on permalinks with Isso.
  * [`markdown`](https://github.com/shaarli/Shaarli/blob/master/plugins/markdown/README.md): Render shaare description with Markdown syntax.
  * `piwik`: A plugin that adds Piwik tracking code to Shaarli pages.
  * [`playvideos`](https://github.com/shaarli/Shaarli/blob/master/plugins/playvideos/README.md): Add a button in the toolbar allowing to watch all videos.
  * `pubsubhubbub`: Enable PubSubHubbub feed publishing
- * `qrcode`: For each link, add a QRCode icon.
- * [`wallabag`](https://github.com/shaarli/Shaarli/blob/master/plugins/wallabag/README.md):  For each link, add a Wallabag icon to save it in your instance.
-
+ * `qrcode`: For each Shaare, add a QRCode icon.
+ * [`wallabag`](https://github.com/shaarli/Shaarli/blob/master/plugins/wallabag/README.md):  For each Shaare, add a Wallabag icon to save it in your instance.
 
 
-#### Third party plugins
+### Third party plugins
 
-See [Community & related software](https://shaarli.readthedocs.io/en/master/Community-&-Related-software/)
+See [Community & related software](https://shaarli.readthedocs.io/en/master/Community-and-Related-software/)
index 11bd1cd22f9a62a275ef3b5ce8570849545bb00e..01071d8e550775d7836d99a6129ca5871a7a3d27 100644 (file)
-## Usage and Prerequisites
+# REST API
 
-See the [REST API documentation](http://shaarli.github.io/api-documentation/)
-for a list of available endpoints and parameters.
+## Server requirements
 
-Please ensure that your server meets the
-[requirements](Server-configuration#prerequisites) and is properly
-[configured](Server-configuration):
+See the **[REST API documentation](http://shaarli.github.io/api-documentation/)** for a list of available endpoints and parameters.
+
+Please ensure that your server meets the requirements and is properly [configured](Server-configuration):
 
 - URL rewriting is enabled (see specific Apache and Nginx sections)
 - the server's timezone is properly defined
-- the server's clock is synchronized with
-  [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol)
-
-The host where the API client is invoked should also be synchronized with NTP,
-see [token expiration](#payload).
-
-## Authentication
-
-All requests to Shaarli's API must include a JWT token to verify their authenticity.
-
-This token has to be included as an HTTP header called `Authentication: Bearer <jwt token>`.
-
-JWT resources :
-
-- [jwt.io](https://jwt.io) (including a list of client per language).
-- RFC : https://tools.ietf.org/html/rfc7519
-- https://float-middle.com/json-web-tokens-jwt-vs-sessions/
-- HackerNews thread: https://news.ycombinator.com/item?id=11929267
-
-
-### Shaarli JWT Token
-
-JWT tokens are composed by three parts, separated by a dot `.` and encoded in base64:
-
-```
-[header].[payload].[signature]
-```
-
-#### Header
-
-Shaarli only allow one hash algorithm, so the header will always be the same:
-
-```json
-{
-    "typ": "JWT",
-    "alg": "HS512"
-}
-```
-
-Encoded in base64, it gives:
-
-```
-ewogICAgICAgICJ0eXAiOiAiSldUIiwKICAgICAgICAiYWxnIjogIkhTNTEyIgogICAgfQ==
-```
-
-#### Payload
-
-**Token expiration**
-
-To avoid infinite token validity, JWT tokens must include their creation date
-in UNIX timestamp format (timezone independent - UTC) under the key `iat` (issued at).
-This token will be valid during **9 minutes**.
-
-```json
-{
-    "iat": 1468663519
-}
-```
-
-See [RFC reference](https://tools.ietf.org/html/rfc7519#section-4.1.6).
-
+- the server's clock is synchronized with [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol)
 
-#### Signature
-
-The signature authenticate the token validity. It contains the base64 of the header and the body, separated by a dot `.`, hashed in SHA512 with the API secret available in Shaarli administration page.
-
-Signature example with PHP:
-
-```php
-$content = base64_encode($header) . '.' . base64_encode($payload);
-$signature = hash_hmac('sha512', $content, $secret);
-```
+The host where the API client is invoked should also be synchronized with NTP, see _payload/token expiration_
 
 
 ## Clients and examples
-### Android, Java, Kotlin
-
-- [Android client example with Kotlin](https://gitlab.com/snippets/1665808)
-  by [Braincoke](https://github.com/Braincoke)
-
-### Javascript, NodeJS
 
-- [shaarli-client](https://www.npmjs.com/package/shaarli-client)
-  ([source code](https://github.com/laBecasse/shaarli-client))
-  by [laBecasse](https://github.com/laBecasse)
+- **[python-shaarli-client](https://github.com/shaarli/python-shaarli-client)** - the reference API client ([Documentation](http://python-shaarli-client.readthedocs.io/en/latest/))
+- [shaarli-client](https://www.npmjs.com/package/shaarli-client) - NodeJs client ([source code](https://github.com/laBecasse/shaarli-client)) by [laBecasse](https://github.com/laBecasse)
+- [Android client example with Kotlin](https://gitlab.com/snippets/1665808) by [Braincoke](https://github.com/Braincoke)
 
-### PHP
 
 This example uses the [PHP cURL](http://php.net/manual/en/book.curl.php) library.
 
@@ -145,13 +68,57 @@ function getInfo($baseUrl, $secret) {
 var_dump(getInfo($baseUrl, $secret));
 ```
 
+## Implementation
+
+### Authentication
+
+- All requests to Shaarli's API must include a **JWT token** to verify their authenticity.
+- This token must be included as an HTTP header called `Authentication: Bearer <jwt token>`.
+- JWT tokens are composed by three parts, separated by a dot `.` and encoded in base64:
+
+```
+[header].[payload].[signature]
+```
+
+##### Header
+
+Shaarli only allow one hash algorithm, so the header will always be the same:
+
+```json
+{
+    "typ": "JWT",
+    "alg": "HS512"
+}
+```
+
+Encoded in base64, it gives:
 
-### Python
+```
+ewogICAgICAgICJ0eXAiOiAiSldUIiwKICAgICAgICAiYWxnIjogIkhTNTEyIgogICAgfQ==
+```
+
+##### Payload
+
+Token expiration: To avoid infinite token validity, JWT tokens must include their creation date in UNIX timestamp format (timezone independent - UTC) under the key `iat` (issued at) field ([1](https://tools.ietf.org/html/rfc7519#section-4.1.6)). This token will be valid during **9 minutes**.
+
+```json
+{
+    "iat": 1468663519
+}
+```
+
+##### Signature
+
+The signature authenticates the token validity. It contains the base64 of the header and the body, separated by a dot `.`, hashed in SHA512 with the API secret available in Shaarli administration page.
+
+Example signature with PHP:
+
+```php
+$content = base64_encode($header) . '.' . base64_encode($payload);
+$signature = hash_hmac('sha512', $content, $secret);
+```
 
-See the reference API client:
 
-- [Documentation](http://python-shaarli-client.readthedocs.io/en/latest/) on ReadTheDocs
-- [python-shaarli-client](https://github.com/shaarli/python-shaarli-client) on Github
 
 ## Troubleshooting
 
@@ -171,3 +138,13 @@ to get the actual error message in the HTTP response body with:
   }
 }
 ```
+
+## References
+
+- [jwt.io](https://jwt.io) (including a list of client per language).
+- [RFC - JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519)
+- [JSON Web Tokens (JWT) vs Sessions](https://float-middle.com/json-web-tokens-jwt-vs-sessions/), [HackerNews thread](https://news.ycombinator.com/item?id=11929267)
+
+
+
+
diff --git a/doc/md/RSS-feeds.md b/doc/md/RSS-feeds.md
deleted file mode 100644 (file)
index ecbff09..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-### Feeds options
-
-Feeds are available in ATOM with `/feed/atom` and RSS with `/feed/rss`.
-
-Options:
-
-- You can use `permalinks` in the feed URL to get permalink to Shaares instead of direct link to shaared URL.
-    - E.G. `https://my.shaarli.domain/feed/atom?permalinks`.
-- You can use `nb` parameter in the feed URL to specify the number of Shaares you want in a feed (default if not specified: `50`). The keyword `all` is available if you want everything.
-    - `https://my.shaarli.domain/feed/atom?permalinks&nb=42`
-    - `https://my.shaarli.domain/feed/atom?permalinks&nb=all`
-
-### RSS Feeds or Picture Wall for a specific search/tag
-
-It is possible to filter RSS/ATOM feeds and Picture Wall on a Shaarli to **only display results of a specific search, or for a specific tag**.
-
-For example, if you want to subscribe only to links tagged `photography`:
-
-- Go to the desired Shaarli instance.
-- Search for the `photography` tag in the _Filter by tag_ box. Links tagged `photography` are displayed.
-- Click on the `RSS Feed` button.
-- You are presented with an RSS feed showing only these links. Subscribe to it to receive only updates with this tag.
-- The same method **also works for a full-text search** (_Search_ box) **and for the Picture Wall** (want to only see pictures about `nature`?)
-- You can also build the URLs manually:
-    - `https://my.shaarli.domain/?do=rss&searchtags=nature`
-    - `https://my.shaarli.domain/links/picture-wall?searchterm=poney`
-
-![](images/rss-filter-1.png) ![](images/rss-filter-2.png)
diff --git a/doc/md/Release-Shaarli.md b/doc/md/Release-Shaarli.md
deleted file mode 100644 (file)
index e22eabc..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-See  [Git - Maintaining a project - Tagging your 
-releases](http://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#Tagging-Your-Releases).
-
-## Prerequisites
-This guide assumes that you have:
-
-- a GPG key matching your GitHub authentication credentials
-    - i.e., the email address identified by the GPG key is the same as the one in your `~/.gitconfig` 
-- a GitHub fork of Shaarli
-- a local clone of your Shaarli fork, with the following remotes:
-    - `origin` pointing to your GitHub fork
-    - `upstream` pointing to the main Shaarli repository
-- maintainer permissions on the main Shaarli repository, to:
-    - push the signed tag
-    - create a new release
-- [Composer](https://getcomposer.org/) needs to be installed
-- The [venv](https://docs.python.org/3/library/venv.html) Python 3 module needs to be installed for HTML documentation generation.
-
-## GitHub release draft and `CHANGELOG.md`
-See http://keepachangelog.com/en/0.3.0/ for changelog formatting.
-
-### GitHub release draft
-GitHub allows drafting the release note for the upcoming release, from the [Releases](https://github.com/shaarli/Shaarli/releases) page. This way, the release note can be drafted while contributions are merged to `master`.
-
-### `CHANGELOG.md`
-This file should contain the same information as the release note draft for the upcoming version.
-
-Update it to:
-
-- add new entries (additions, fixes, etc.)
-- mark the current version as released by setting its date and link
-- add a new section for the future unreleased version
-
-```bash
-$ cd /path/to/shaarli
-
-$ nano CHANGELOG.md
-
-[...]
-## vA.B.C - UNRELEASED
-TBA
-
-## [vX.Y.Z](https://github.com/shaarli/Shaarli/releases/tag/vX.Y.Z) - YYYY-MM-DD
-[...]
-```
-
-
-## Increment the version code, update docs, create and push a signed tag
-### Update the list of Git contributors
-```bash
-$ make authors
-$ git commit -s -m "Update AUTHORS"
-```
-
-### Create and merge a Pull Request
-This one is pretty straightforward ;-)
-
-### Bump Shaarli version to v0.x branch
-
-```bash
-$ git checkout master
-$ git fetch upstream
-$ git pull upstream master
-
-# IF the branch doesn't exists
-$ git checkout -b v0.5
-# OR if the branch already exists
-$ git checkout v0.5
-$ git rebase upstream/master
-
-# Bump shaarli version from dev to 0.5.0, **without the `v`**
-$ vim shaarli_version.php
-$ git add shaarli_version
-$ git commit -s -m "Bump Shaarli version to v0.5.0"
-$ git push upstream v0.5
-```
-
-### Create and push a signed tag
-```bash
-# update your local copy
-$ git checkout v0.5
-$ git fetch upstream
-$ git pull upstream v0.5
-
-# create a signed tag
-$ git tag -s -m "Release v0.5.0" v0.5.0
-
-# push it to "upstream"
-$ git push --tags upstream
-```
-
-### Verify a signed tag
-[`v0.5.0`](https://github.com/shaarli/Shaarli/releases/tag/v0.5.0) is the first GPG-signed tag pushed on the Community Shaarli.
-
-Let's have a look at its signature!
-
-```bash
-$ cd /path/to/shaarli
-$ git fetch upstream
-
-# get the SHA1 reference of the tag
-$ git show-ref tags/v0.5.0
-f7762cf803f03f5caf4b8078359a63783d0090c1 refs/tags/v0.5.0
-
-# verify the tag signature information
-$ git verify-tag f7762cf803f03f5caf4b8078359a63783d0090c1
-gpg: Signature made Thu 30 Jul 2015 11:46:34 CEST using RSA key ID 4100DF6F
-gpg: Good signature from "VirtualTam <virtualtam@flibidi.net>" [ultimate]
-```
-
-## Publish the GitHub release
-### Update release badges
-Update `README.md` so version badges display and point to the newly released Shaarli version(s), in the `master` branch.
-
-### Create a GitHub release from a Git tag
-From the previously drafted release:
-
-- edit the release notes (if needed)
-- specify the appropriate Git tag
-- publish the release
-- profit!
-
-### Generate and upload all-in-one release archives
-Users with a shared hosting may have:
-
-- no SSH access
-- no possibility to install PHP packages or server extensions
-- no possibility to run scripts
-
-To ease Shaarli installations, it is possible to generate and upload additional release archives,
-that will contain Shaarli code plus all required third-party libraries.
-
-**From the `v0.5` branch:**
-
-```bash
-$ make release_archive
-```
-
-This will create the following archives:
-
-- `shaarli-vX.Y.Z-full.tar`
-- `shaarli-vX.Y.Z-full.zip`
-
-The archives need to be manually uploaded on the previously created GitHub release.
-
-### Update `stable` and `latest` branches
-
-```
-$ git checkout latest
-# latest release
-$ git merge v0.5.0
-# fix eventual conflicts
-$ make test
-$ git push upstream latest
-$ git checkout stable
-# latest previous major
-$ git merge v0.4.5 
-# fix eventual conflicts
-$ make test
-$ git push upstream stable
-```
diff --git a/doc/md/Reverse-proxy.md b/doc/md/Reverse-proxy.md
new file mode 100644 (file)
index 0000000..b7e347d
--- /dev/null
@@ -0,0 +1,141 @@
+# Reverse proxy
+
+If Shaarli is hosted on a server behind a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) (i.e. there is a proxy server between clients and the web server hosting Shaarli), configure it accordingly. See [Reverse proxy](Reverse-proxy.md) configuration. In this example:
+
+- The Shaarli application server exposes port `10080` to the proxy (for example docker container started with `--publish 127.0.0.1:10080:80`).
+- The Shaarli application server runs at `127.0.0.1` (container). Replace with the server's IP address if running on a different machine.
+- Shaarli's Fully Qualified Domain Name (FQDN) is `shaarli.mydomain.org`.
+- No HTTPS is setup on the application server, SSL termination is done at the reverse proxy.
+
+In your [Shaarli configuration](Shaarli-configuration) `data/config.json.php`, add the public IP of your proxy under `security.trusted_proxies`.
+
+See also [proxy-related](https://github.com/shaarli/Shaarli/issues?utf8=%E2%9C%93&q=label%3Aproxy+) issues.
+
+
+## Apache
+
+```apache
+<VirtualHost *:80>
+    ServerName shaarli.mydomain.org
+
+    # For SSL/TLS certificates acquired with certbot or self-signed certificates
+    # Redirect HTTP requests to HTTPS, except Let's Encrypt ACME challenge requests
+    RewriteEngine on
+    RewriteRule ^.well-known/acme-challenge/ - [L]
+    RewriteCond %{HTTP_HOST} =shaarli.mydomain.org
+    RewriteRule  ^ https://shaarli.mydomain.org%{REQUEST_URI} [END,NE,R=permanent]
+</VirtualHost>
+
+# SSL/TLS configuration for Let's Encrypt certificates managed with mod_md
+#MDomain shaarli.mydomain.org
+#MDCertificateAgreement accepted
+#MDContactEmail admin@shaarli.mydomain.org
+#MDPrivateKeys RSA 4096
+
+<VirtualHost *:443>
+    ServerName shaarli.mydomain.org
+
+    # SSL/TLS configuration for Let's Encrypt certificates acquired with certbot standalone
+    SSLEngine             on
+    SSLCertificateFile    /etc/letsencrypt/live/shaarli.mydomain.org/fullchain.pem
+    SSLCertificateKeyFile /etc/letsencrypt/live/shaarli.mydomain.org/privkey.pem
+    # Let's Encrypt settings from https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/tls_configs/current-options-ssl-apache.conf
+    SSLProtocol             all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
+    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+    SSLHonorCipherOrder     off
+    SSLSessionTickets       off
+    SSLOptions +StrictRequire
+
+    # SSL/TLS configuration for self-signed certificates
+    #SSLEngine             on
+    #SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
+    #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
+
+    # let the proxied shaarli server/container know HTTPS URLs should be served
+    RequestHeader set X-Forwarded-Proto "https"
+
+    # send the original SERVER_NAME to the proxied host
+    ProxyPreserveHost On
+    
+    # pass requests to the proxied host
+    # sets X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Server headers
+    ProxyPass        / http://127.0.0.1:10080/
+    ProxyPassReverse / http://127.0.0.1:10080/
+</VirtualHost>
+```
+
+
+## HAProxy
+
+
+```conf
+global
+    [...]
+
+defaults
+    [...]
+
+frontend http-in
+    bind :80
+    redirect scheme https code 301 if !{ ssl_fc }
+    bind :443 ssl crt /path/to/cert.pem
+    default_backend shaarli
+
+backend shaarli
+    mode http
+    option http-server-close
+    option forwardfor
+    reqadd X-Forwarded-Proto: https
+    server shaarli1 127.0.0.1:10080
+```
+
+- [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/)
+
+## Nginx
+
+
+```nginx
+http {
+    [...]
+
+    index index.html index.php;
+
+    root        /home/john/web;
+    access_log  /var/log/nginx/access.log combined;
+    error_log   /var/log/nginx/error.log;
+
+    server {
+        listen       80;
+        server_name  shaarli.mydomain.org;
+        # redirect HTTP to HTTPS
+        return       301 https://shaarli.mydomain.org$request_uri;
+    }
+
+    server {
+        listen       443 ssl http2;
+        server_name  shaarli.mydomain.org;
+
+        ssl_certificate       /path/to/certificate
+        ssl_certificate_key   /path/to/private/key
+
+        location / {
+            proxy_set_header  X-Real-IP         $remote_addr;
+            proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
+            proxy_set_header  X-Forwarded-Proto $scheme;
+            proxy_set_header  X-Forwarded-Host  $host;
+
+            # pass requests to the proxied host
+            proxy_pass             http://localhost:10080/;
+            proxy_set_header Host  $host;
+            proxy_connect_timeout  30s;
+            proxy_read_timeout     120s;
+        }
+    }
+}
+```
+
+## References
+
+- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto)
+- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host)
+- [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For)
diff --git a/doc/md/Security.md b/doc/md/Security.md
deleted file mode 100644 (file)
index 65db422..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-## Client browser
-- Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or masqueraded `HTTP_REFERER` in your browser, some features of Shaarli may not work
-
-## Server and sessions
-- Directories are protected using `.htaccess` files
-- Forms are protected against XSRF (Cross-site requests forgery):
-    - Forms which act on data (save,delete…) contain a token generated by the server.
-    - Any posted form which does not contain a valid token is rejected.
-    - Any token can only be used once.
-    - Tokens are attached to the session and cannot be reused in another session.
-- Sessions automatically expire after 60 minutes.
-- Sessions are protected against hijacking: the session ID cannot be used from a different IP address.
-
-## Shaarli datastore and configuration
-- The password is salted, hashed and stored in the data subdirectory, in a PHP file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks.
-- Links are stored as an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a `.php` file.
-- Even if the server does not support `.htaccess` files, the data file will still not be readable by URL.
-- The database looks like this:
-
-```php
-<?php /* zP1ZjxxJtiYIvvevEPJ2lDOaLrZv7o...
-...ka7gaco/Z+TFXM2i7BlfMf8qxpaSSYfKlvqv/x8= */ ?>
-```
-
-- Small hashes are used to make a link to an entry in Shaarli. They are unique. In fact, the date of the items (eg. `20110923_150523`) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only `A-Z a-z 0-9 - _` and `@`.
index f9ea2ed2145801f79c99819750f06b700b7876c8..297d7c291e83c0b024137f16f614676a769f1aaa 100644 (file)
@@ -1,20 +1,46 @@
+# Server configuration
 
-- [Prerequisites](#prerequisistes)
-- [Apache](#apache)
-- [Nginx](#nginx)
-- [Proxies](#proxies)
-- [See also](#see-also)
+## Requirements
 
-## Prerequisites
-### Shaarli
+### Operating system and web server
 
-- A web server and PHP interpreter module/service have been installed.
-- You have write access to the Shaarli installation directory.
-- The correct read/write permissions have been granted to the web server user and group.
-- Your PHP interpreter is compatible with supported PHP versions:
+Shaarli can be hosted on dedicated/virtual servers, or shared hosting.
+
+You need write access to the Shaarli installation directory - you should have received instructions from your hosting provider on how to connect to the server using SSH (or FTP for shared hosts).
+
+Examples in this documentation are given for [Debian](https://www.debian.org/), a GNU/Linux distribution widely used in server environments. Please adapt them to your specific Linux distribution.
+
+A $5/month VPS (1 CPU, 1 GiB RAM and 25 GiB SSD) will run any Shaarli installation without problems. Some hosting providers: [DigitalOcean](https://www.digitalocean.com/) ([1](https://www.digitalocean.com/docs/droplets/overview/), [2](https://www.digitalocean.com/pricing/), [3](https://www.digitalocean.com/docs/droplets/how-to/create/), [4](https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/), [5](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-debian-8), [6](https://www.digitalocean.com/community/tutorials/an-introduction-to-securing-your-linux-vps)), [Gandi](https://www.gandi.net/en), [OVH](https://www.ovh.co.uk/), [RackSpace](https://www.rackspace.com/), etc.
+
+
+### Network and domain name
+
+Try to host the server in a region that is geographically close to your users.
+
+A **domain name** ([DNS record](https://opensource.com/article/17/4/introduction-domain-name-system-dns)) pointing to the server's public IP address is required to obtain a SSL/TLS certificate and setup HTTPS to secure client traffic to your Shaarli instance.
+
+You can obtain a domain name from a [registrar](https://en.wikipedia.org/wiki/Domain_name_registrar) ([1](https://www.ovh.co.uk/domains), [2](https://www.gandi.net/en/domain)), or from free subdomain providers ([1](https://freedns.afraid.org/)). If you don't have a domain name, please set up a private domain name ([FQDN](ttps://en.wikipedia.org/wiki/Fully_qualified_domain_name)) in your clients' [hosts files](https://en.wikipedia.org/wiki/Hosts_(file)) to access the server (direct access by IP address can result in unexpected behavior).
+
+Setup a **firewall** (using `iptables`, [ufw](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-with-ufw-on-debian-10), [fireHOL](https://firehol.org/) or any frontend of your choice) to deny all incoming traffic except `tcp/80` and `tcp/443`, which are needed to access the web server (and any other posrts you might need, like SSH). If the server is in a private network behind a NAT, ensure these **ports are forwarded** to the server.
+
+Shaarli makes outbound HTTP/HTTPS connections to websites you bookmark to fetch page information (title, thumbnails), the server must then have access to the Internet as well, and a working DNS resolver.
+
+
+### Screencast
+
+Here is a screencast of the installation procedure
+
+[![asciicast](https://asciinema.org/a/z3RXxcJIRgWk0jM2ws6EnUFgO.svg)](https://asciinema.org/a/z3RXxcJIRgWk0jM2ws6EnUFgO)
+
+--------------------------------------------------------------------------------
+
+### PHP
+
+Supported PHP versions:
 
 Version | Status | Shaarli compatibility
 :---:|:---:|:---:
+7.3 | Supported | Yes
 7.2 | Supported | Yes
 7.1 | Supported | Yes
 7.0 | EOL: 2018-12-03 | Yes (up to Shaarli 0.10.x)
@@ -23,420 +49,398 @@ Version | Status | Shaarli compatibility
 5.4 | EOL: 2015-09-14 | Yes (up to Shaarli 0.8.x)
 5.3 | EOL: 2014-08-14 | Yes (up to Shaarli 0.8.x)
 
-- The following PHP extensions are installed on the server:
+Required PHP extensions:
 
 Extension | Required? | Usage
 ---|:---:|---
-[`openssl`](http://php.net/manual/en/book.openssl.php) | All | OpenSSL, HTTPS
+[`openssl`](http://php.net/manual/en/book.openssl.php) | requires | OpenSSL, HTTPS
 [`php-json`](http://php.net/manual/en/book.json.php) | required | configuration parsing
+[`php-simplexml`](https://www.php.net/manual/en/book.simplexml.php) | required | REST API (Slim framework)
 [`php-mbstring`](http://php.net/manual/en/book.mbstring.php) | CentOS, Fedora, RHEL, Windows, some hosting providers | multibyte (Unicode) string support
 [`php-gd`](http://php.net/manual/en/book.image.php) | optional | required to use thumbnails
 [`php-intl`](http://php.net/manual/en/book.intl.php) | optional | localized text sorting (e.g. `e->è->f`)
 [`php-curl`](http://php.net/manual/en/book.curl.php) | optional | using cURL for fetching webpages and thumbnails in a more robust way
 [`php-gettext`](http://php.net/manual/en/book.gettext.php) | optional | Use the translation system in gettext mode (faster)
---------------------------------------------------------------------------------
-
-### SSL/TLS configuration 
 
-To setup HTTPS / SSL on your webserver (recommended), you must generate a public/private **key pair** and a **certificate**, and install, configure and activate the appropriate **webserver SSL extension**.
+Some [plugins](Plugins.md) may require additional configuration.
 
-#### Let's Encrypt
+- [PHP: Supported versions](http://php.net/supported-versions.php)
+- [PHP: Unsupported versions (EOL/End-of-life)](http://php.net/eol.php)
+- [PHP 7 Changelog](http://php.net/ChangeLog-7.php)
+- [PHP 5 Changelog](http://php.net/ChangeLog-5.php)
+- [PHP: Bugs](https://bugs.php.net/)
 
-[Let's Encrypt](https://en.wikipedia.org/wiki/Let%27s_Encrypt) is a certificate authority that provides free TLS/X.509 certificates via an automated process.
 
- * Install `certbot` using the appropriate method described on https://certbot.eff.org/.
-Location of the `certbot` program and template configuration files may vary depending on which installation method was used. Change the file paths below accordingly. Here is an easy way to create a signed certificate using `certbot`, it assumes `certbot` was installed through APT on a Debian-based distribution:
+## SSL/TLS (HTTPS)
 
- * Stop the apache2/nginx service.
- * Run `certbot --agree-tos --standalone --preferred-challenges tls-sni --email "youremail@example.com" --domain yourdomain.example.com`
- * For the Apache webserver, copy `/usr/lib/python2.7/dist-packages/certbot_apache/options-ssl-apache.conf` to `/etc/letsencrypt/options-ssl-apache.conf` (paths may vary depending on installation method)
- * For Nginx: TODO
- * Setup your webserver as described below
- * Restart the apache2/nginx service.
+We recommend setting up [HTTPS](https://en.wikipedia.org/wiki/HTTPS) (SSL/[TLS](https://en.wikipedia.org/wiki/Transport_Layer_Security)) on your webserver for secure communication between clients and the server.
 
-#### Self-signed certificates
+### Let's Encrypt
 
-If you don't want to request a certificate from Let's Encrypt, or are unable to (for example, webserver on a LAN, or domain name not registered in the public DNS system), you can generate a self-signed certificate. This certificate will trigger security warnings in web browsers, unless you add it to the browser's SSL store manually.
+For public-facing web servers this can be done using free SSL/TLS certificates from [Let's Encrypt](https://en.wikipedia.org/wiki/Let's_Encrypt), a non-profit certificate authority provididing free certificates.
 
-* Apache: run `make-ssl-cert generate-default-snakeoil --force-overwrite`
-* Nginx: TODO
+ - [How to secure Apache with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-apache-with-let-s-encrypt-on-debian-10)
+ - [How to secure Nginx with Let's Encrypt](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-debian-10)
+ - [How To Use Certbot Standalone Mode to Retrieve Let's Encrypt SSL Certificates](https://www.digitalocean.com/community/tutorials/how-to-use-certbot-standalone-mode-to-retrieve-let-s-encrypt-ssl-certificates-on-debian-10).
 
---------------------------------------------------------------------------------
+In short:
 
-## Apache
+```bash
+# install certbot
+sudo apt install certbot
 
-Here is a basic configuration example for the Apache web server with `mod_php`.
+# stop your webserver if you already have one running
+# certbot in standalone mode needs to bind to port 80 (only needed on initial generation)
+sudo systemctl stop apache2
+sudo systemctl stop nginx
 
-In `/etc/apache2/sites-available/shaarli.conf`:
+# generate initial certificates
+# Let's Encrypt ACME servers must be able to access your server! port forwarding and firewall must be properly configured
+sudo certbot certonly --standalone --noninteractive --agree-tos --email "admin@shaarli.mydomain.org" -d shaarli.mydomain.org
+# this will generate a private key and certificate at /etc/letsencrypt/live/shaarli.mydomain.org/{privkey,fullchain}.pem
 
-```apache
-<VirtualHost *:443>
-    ServerName   shaarli.my-domain.org
-    DocumentRoot /absolute/path/to/shaarli/
+# restart the web server
+sudo systemctl start apache2
+sudo systemctl start nginx
+```
 
-    # Logging
-    # Possible values include: debug, info, notice, warn, error, crit, alert, emerg.
-    LogLevel  warn
-    ErrorLog  /var/log/apache2/shaarli-error.log
-    CustomLog /var/log/apache2/shaarli-access.log combined
+On apache `2.4.43+`, you can also delegate LE certificate management to [mod_md](https://httpd.apache.org/docs/2.4/mod/mod_md.html) [[1](https://www.cyberciti.biz/faq/how-to-secure-apache-with-mod_md-lets-encrypt-on-ubuntu-20-04-lts/)] in which case you don't need certbot and manual SSL configuration in virtualhosts.
 
-    # Let's Encrypt SSL configuration (recommended)
-    SSLEngine             on
-    SSLCertificateFile    /etc/letsencrypt/live/yourdomain.example.com/fullchain.pem
-    SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.example.com/privkey.pem
-    Include /etc/letsencrypt/options-ssl-apache.conf
+### Self-signed
 
-    # Self-signed SSL cert configuration
-    #SSLEngine             on
-    #SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
-    #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
+If you don't want to rely on a certificate authority, or the server can only be accessed from your own network, you can also generate self-signed certificates. Not that this will generate security warnings in web browsers/clients trying to access Shaarli:
 
-    # Optional, log PHP errors, useful for debugging
-    #php_flag  log_errors on
-    #php_flag  display_errors on
-    #php_value error_reporting 2147483647
-    #php_value error_log /var/log/apache2/shaarli-php-error.log
+- [How To Create a Self-Signed SSL Certificate for Apache](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-on-debian-10)
+- [How To Create a Self-Signed SSL Certificate for Nginx](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-on-debian-10)
+- [How to Create Self-Signed SSL Certificates with OpenSSL](http://www.xenocafe.com/tutorials/linux/centos/openssl/self_signed_certificates/index.php)
+- [How do I create my own Certificate Authority?](https://workaround.org/certificate-authority)
 
-    <Directory /absolute/path/to/shaarli/>
-        #Required for .htaccess support
-        AllowOverride All
-        Order allow,deny
-        Allow from all
+--------------------------------------------------------------------------------
 
-        Options Indexes FollowSymLinks MultiViews #TODO is Indexes/Multiviews required?
+## Examples
 
-        # Optional - required for playvideos plugin
-        #Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'"
-    </Directory>
+The following examples assume a Debian-based operating system is installed. On other distributions you may have to adapt details such as package installation procedures, configuration file locations, and webserver username/group (`www-data` or `httpd` are common values). In these examples we assume the document root for your web server/virtualhost is at `/var/www/shaarli.mydomain.org/`:
 
-</VirtualHost>
+```bash
+# create the document root (replace with your own domain name)
+sudo mkdir -p /var/www/shaarli.mydomain.org/
 ```
 
-Enable this configuration with `sudo a2ensite shaarli`
+You can install Shaarli at the root of your virtualhost, or in a subdirectory as well. See [Directory structure](Directory-structure)
 
-_Note: If you use Apache 2.2 or lower, you need [mod_version](https://httpd.apache.org/docs/current/mod/mod_version.html) to be installed and enabled._
 
-_Note: Apache module `mod_rewrite` must be enabled to use the REST API._
+### Apache
 
+```bash
+# Install apache + mod_php and PHP modules
+sudo apt update
+sudo apt install apache2 libapache2-mod-php php-json php-mbstring php-gd php-intl php-curl php-gettext
 
-## Nginx
+# Edit the virtualhost configuration file with your favorite editor (replace the example domain name)
+sudo nano /etc/apache2/sites-available/shaarli.mydomain.org.conf
+```
 
-Here is a basic configuration example for the Nginx web server, using the [php-fpm](http://php-fpm.org) PHP FastCGI Process Manager, and Nginx's [FastCGI](https://en.wikipedia.org/wiki/FastCGI) module.
+```apache
+<VirtualHost *:80>
+    ServerName shaarli.mydomain.org
+    DocumentRoot /var/www/shaarli.mydomain.org/
+
+    # For SSL/TLS certificates acquired with certbot or self-signed certificates
+    # Redirect HTTP requests to HTTPS, except Let's Encrypt ACME challenge requests
+    RewriteEngine on
+    RewriteRule ^.well-known/acme-challenge/ - [L]
+    RewriteCond %{HTTP_HOST} =shaarli.mydomain.org
+    RewriteRule  ^ https://shaarli.mydomain.org%{REQUEST_URI} [END,NE,R=permanent]
+</VirtualHost>
 
-<!--- TODO refactor everything below this point --->
+# SSL/TLS configuration for Let's Encrypt certificates managed with mod_md
+#MDomain shaarli.mydomain.org
+#MDCertificateAgreement accepted
+#MDContactEmail admin@shaarli.mydomain.org
+#MDPrivateKeys RSA 4096
+
+<VirtualHost *:443>
+    ServerName   shaarli.mydomain.org
+    DocumentRoot /var/www/shaarli.mydomain.org/
 
-### Common setup
-Once Nginx and PHP-FPM are installed, we need to ensure:
+    # SSL/TLS configuration for Let's Encrypt certificates acquired with certbot standalone
+    SSLEngine             on
+    SSLCertificateFile    /etc/letsencrypt/live/shaarli.mydomain.org/fullchain.pem
+    SSLCertificateKeyFile /etc/letsencrypt/live/shaarli.mydomain.org/privkey.pem
+    # Let's Encrypt settings from https://github.com/certbot/certbot/blob/master/certbot-apache/certbot_apache/_internal/tls_configs/current-options-ssl-apache.conf
+    SSLProtocol             all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
+    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
+    SSLHonorCipherOrder     off
+    SSLSessionTickets       off
+    SSLOptions +StrictRequire
+
+    # SSL/TLS configuration for self-signed certificates
+    #SSLEngine             on
+    #SSLCertificateFile    /etc/ssl/certs/ssl-cert-snakeoil.pem
+    #SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
 
-- Nginx and PHP-FPM are running using the _same user and group_
-- both these user and group have
-    - `read` permissions for Shaarli resources
-    - `execute` permissions for Shaarli directories _AND_ their parent directories
+    # Optional, log PHP errors, useful for debugging
+    #php_flag  log_errors on
+    #php_flag  display_errors on
+    #php_value error_reporting 2147483647
+    #php_value error_log /var/log/apache2/shaarli-php-error.log
 
-On a production server:
+    <Directory /var/www/shaarli.mydomain.org/>
+        # Required for .htaccess support
+        AllowOverride All
+        Require all granted
+    </Directory>
 
-- `user:group` will likely be `http:http`, `www:www` or `www-data:www-data`
-- files will be located under `/var/www`, `/var/http` or `/usr/share/nginx`
+    <LocationMatch "/\.">
+        # Prevent accessing dotfiles
+        RedirectMatch 404 ".*"
+    </LocationMatch>
 
-On a development server:
+    <LocationMatch "\.(?:ico|css|js|gif|jpe?g|png)$">
+        # allow client-side caching of static files
+        Header set Cache-Control "max-age=2628000, public, must-revalidate, proxy-revalidate"
+    </LocationMatch>
 
-- files may be located in a user's home directory
-- in this case, make sure both Nginx and PHP-FPM are running as the local user/group!
+    # serve the Shaarli favicon from its custom location
+    Alias favicon.ico /var/www/shaarli.mydomain.org/images/favicon.ico
 
-For all following configuration examples, this user/group pair will be used:
+</VirtualHost>
+```
 
-- `user:group = john:users`,
+```bash
+# Enable the virtualhost
+sudo a2ensite shaarli.mydomain.org
 
-which corresponds to the following service configuration:
+# mod_ssl must be enabled to use TLS/SSL certificates
+# https://httpd.apache.org/docs/current/mod/mod_ssl.html
+sudo a2enmod ssl
 
-```ini
-; /etc/php/php-fpm.conf
-user = john
-group = users
+# mod_rewrite must be enabled to use the REST API
+# https://httpd.apache.org/docs/current/mod/mod_rewrite.html
+sudo a2enmod rewrite
 
-[...]
-listen.owner = john
-listen.group = users
-```
+# mod_headers must be enabled to set custom headers from the server config
+sudo a2enmod headers
 
-```nginx
-# /etc/nginx/nginx.conf
-user john users;
+# mod_version must only be enabled if you use Apache 2.2 or lower
+# https://httpd.apache.org/docs/current/mod/mod_version.html
+# sudo a2enmod version
 
-http {
-    [...]
-}
+# restart the apache service
+sudo systemctl restart apache2
 ```
 
-### (Optional) Increase the maximum file upload size
-Some bookmark dumps generated by web browsers can be _huge_ due to the presence of Base64-encoded images and favicons, as well as extra verbosity when nesting links in (sub-)folders.
+- [How to install the Apache web server](https://www.digitalocean.com/community/tutorials/how-to-install-the-apache-web-server-on-debian-10)
+- [Apache/PHP - error log per VirtualHost - StackOverflow](http://stackoverflow.com/q/176)
+- [Apache - PHP: php_value vs php_admin_value and the use of php_flag explained](https://ma.ttias.be/php-php_value-vs-php_admin_value-and-the-use-of-php_flag-explained/)
+- [Server-side TLS (Apache) - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS#Apache)
+- [Apache 2.4 documentation](https://httpd.apache.org/docs/2.4/)
+- [Apache mod_proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html)
+- [Apache Reverse Proxy Request Headers](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#x-headers)
 
-To increase upload size, you will need to modify both nginx and PHP configuration:
 
-```nginx
-# /etc/nginx/nginx.conf
+### Nginx
 
-http {
-    [...]
+This examples uses nginx and the [PHP-FPM](https://www.digitalocean.com/community/tutorials/how-to-install-linux-nginx-mariadb-php-lemp-stack-on-debian-10#step-3-%E2%80%94-installing-php-for-processing) PHP interpreter. Nginx and PHP-FPM must be running using the same user and group, here we assume the user/group to be `www-data:www-data`.
 
-    client_max_body_size 10m;
 
-    [...]
-}
-```
-
-```ini
-# /etc/php/<PHP_VERSION>/fpm/php.ini
+```bash
+# install nginx and php-fpm
+sudo apt update
+sudo apt install nginx php-fpm
 
-[...]
-post_max_size = 10M
-[...]
-upload_max_filesize = 10M
+# Edit the virtualhost configuration file with your favorite editor
+sudo nano /etc/nginx/sites-available/shaarli.mydomain.org
 ```
 
-### Minimal
-_WARNING: Use for development only!_ 
-
 ```nginx
-user john users;
-worker_processes  1;
-events {
-    worker_connections  1024;
+server {
+    listen       80;
+    server_name  shaarli.mydomain.org;
+
+    # redirect all plain HTTP requests to HTTPS
+    return 301 https://shaarli.mydomain.org$request_uri;
 }
 
-http {
-    include            mime.types;
-    default_type       application/octet-stream;
-    keepalive_timeout  20;
-
-    index index.html index.php;
-
-    server {
-        listen       80;
-        server_name  localhost;
-        root         /home/john/web;
-
-        access_log  /var/log/nginx/access.log;
-        error_log   /var/log/nginx/error.log;
-
-        location /shaarli/ {
-            try_files $uri /shaarli/index.php$is_args$args;
-            access_log  /var/log/nginx/shaarli.access.log;
-            error_log   /var/log/nginx/shaarli.error.log;
-        }
-
-        location ~ (index)\.php$ {
-            try_files $uri =404;
-            fastcgi_split_path_info ^(.+\.php)(/.+)$;
-            fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
-            fastcgi_index  index.php;
-            include        fastcgi.conf;
-        }
+server {
+    # ipv4 listening port/protocol
+    listen       443 ssl http2;
+    # ipv6 listening port/protocol
+    listen           [::]:443 ssl http2;
+    server_name  shaarli.mydomain.org;
+    root         /var/www/shaarli.mydomain.org;
+
+    # log file locations
+    # combined log format prepends the virtualhost/domain name to log entries
+    access_log  /var/log/nginx/access.log combined;
+    error_log   /var/log/nginx/error.log;
+
+    # paths to private key and certificates for SSL/TLS
+    ssl_certificate      /etc/ssl/shaarli.mydomain.org.crt;
+    ssl_certificate_key  /etc/ssl/private/shaarli.mydomain.org.key;
+
+    # Let's Encrypt SSL settings from https://github.com/certbot/certbot/blob/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf
+    ssl_session_cache shared:le_nginx_SSL:10m;
+    ssl_session_timeout 1440m;
+    ssl_session_tickets off;
+    ssl_protocols TLSv1.2 TLSv1.3;
+    ssl_prefer_server_ciphers off;
+    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
+
+    # increase the maximum file upload size if needed: by default nginx limits file upload to 1MB (413 Entity Too Large error)
+    client_max_body_size 100m;
+
+    # relative path to shaarli from the root of the webserver
+    location / {
+        # default index file when no file URI is requested
+        index index.php;
+        try_files $uri /index.php$is_args$args;
     }
-}
-```
 
-### Modular
-The previous setup is sufficient for development purposes, but has several major caveats:
+    location ~ (index)\.php$ {
+        try_files $uri =404;
+        # slim API - split URL path into (script_filename, path_info)
+        fastcgi_split_path_info ^(.+\.php)(/.+)$;
+        # pass PHP requests to PHP-FPM
+        fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
+        fastcgi_index  index.php;
+        include        fastcgi.conf;
+    }
 
-- every content that does not match the PHP rule will be sent to client browsers:
-    - dotfiles - in our case, `.htaccess`
-    - temporary files, e.g. Vim or Emacs files: `index.php~`
-- asset / static resource caching is not optimized
-- if serving several PHP sites, there will be a lot of duplication: `location /shaarli/`, `location /mysite/`, etc.
+    location ~ \.php$ {
+        # deny access to all other PHP scripts
+        # disable this if you host other PHP applications on the same virtualhost
+        deny all;
+    }
 
-To solve this, we will split Nginx configuration in several parts, that will be included when needed:
+    location ~ /\. {
+        # deny access to dotfiles
+        deny all;
+    }
 
-```nginx
-# /etc/nginx/deny.conf
-location ~ /\. {
-    # deny access to dotfiles
-    access_log off;
-    log_not_found off;
-    deny all;
-}
+    location ~ ~$ {
+        # deny access to temp editor files, e.g. "script.php~"
+        deny all;
+    }
 
-location ~ ~$ {
-    # deny access to temp editor files, e.g. "script.php~"
-    access_log off;
-    log_not_found off;
-    deny all;
-}
-```
+    location = /favicon.ico {
+        # serve the Shaarli favicon from its custom location
+        alias /var/www/shaarli/images/favicon.ico;
+    }
 
-```nginx
-# /etc/nginx/php.conf
-location ~ (index)\.php$ {
-    # Slim - split URL path into (script_filename, path_info)
-    try_files $uri =404;
-    fastcgi_split_path_info ^(.+\.php)(/.+)$;
-
-    # filter and proxy PHP requests to PHP-FPM
-    fastcgi_pass   unix:/var/run/php-fpm/php-fpm.sock;
-    fastcgi_index  index.php;
-    include        fastcgi.conf;
-}
+    # allow client-side caching of static files
+    location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
+        expires    max;
+        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
+        # HTTP 1.0 compatibility
+        add_header Pragma public;
+    }
 
-location ~ \.php$ {
-    # deny access to all other PHP scripts
-    deny all;
 }
 ```
 
-```nginx
-# /etc/nginx/static_assets.conf
-location ~* \.(?:ico|css|js|gif|jpe?g|png)$ {
-    expires    max;
-    add_header Pragma public;
-    add_header Cache-Control "public, must-revalidate, proxy-revalidate";
-}
+```bash
+# enable the configuration/virtualhost
+sudo ln -s /etc/nginx/sites-available/shaarli.mydomain.org /etc/nginx/sites-enabled/shaarli.mydomain.org
+# reload nginx configuration
+sudo systemctl reload nginx
 ```
 
-```nginx
-# /etc/nginx/nginx.conf
-[...]
-
-http {
-    [...]
-
-    root        /home/john/web;
-    access_log  /var/log/nginx/access.log;
-    error_log   /var/log/nginx/error.log;
+- [How to install the Nginx web server](https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-debian-10)
+- [Nginx Beginner's guide](http://nginx.org/en/docs/beginners_guide.html)
+- [Nginx documentation](https://nginx.org/en/docs/)
+- [Nginx ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)
+- [Nginx Pitfalls](http://wiki.nginx.org/Pitfalls)
+- [Nginx PHP configuration examples - Karl Blessing](http://kbeezie.com/nginx-configuration-examples/)
+- [Server-side TLS (Nginx) - Mozilla](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx)
 
-    server {
-        # virtual host for a first domain
-        listen       80;
-        server_name  my.first.domain.org;
 
-        location /shaarli/ {
-            # Slim - rewrite URLs
-            try_files $uri /shaarli/index.php$is_args$args;
 
-            access_log  /var/log/nginx/shaarli.access.log;
-            error_log   /var/log/nginx/shaarli.error.log;
-        }
+## Reverse proxies
 
-        location = /shaarli/favicon.ico {
-            # serve the Shaarli favicon from its custom location
-            alias /var/www/shaarli/images/favicon.ico;
-        }
+If Shaarli is hosted on a server behind a [reverse proxy](https://en.wikipedia.org/wiki/Reverse_proxy) (i.e. there is a proxy server between clients and the web server hosting Shaarli), configure it accordingly. See [Reverse proxy](Reverse-proxy.md) configuration.
 
-        include deny.conf;
-        include static_assets.conf;
-        include php.conf;
-    }
 
-    server {
-        # virtual host for a second domain
-        listen       80;
-        server_name  second.domain.com;
 
-        location /minigal/ {
-            access_log  /var/log/nginx/minigal.access.log;
-            error_log   /var/log/nginx/minigal.error.log;
-        }
+## Allow import of large browser bookmarks export
 
-        include deny.conf;
-        include static_assets.conf;
-        include php.conf;
-    }
-}
-```
+Web browser bookmark exports can be large due to the presence of base64-encoded images and favicons/long subfolder names. Edit the PHP configuration file.
 
-### Redirect HTTP to HTTPS
-Assuming you have generated a (self-signed) key and certificate, and they are
-located under `/home/john/ssl/localhost.{key,crt}`, it is pretty straightforward
-to set an HTTP (:80) to HTTPS (:443) redirection to force SSL/TLS usage.
+- Apache: `/etc/php/<PHP_VERSION>/apache2/php.ini`
+- Nginx + PHP-FPM: `/etc/php/<PHP_VERSION>/fpm/php.ini` (in addition to `client_max_body_size` in the [Nginx configuration](#nginx))
 
-```nginx
-# /etc/nginx/nginx.conf
+```ini
 [...]
+# (optional) increase the maximum file upload size:
+post_max_size = 100M
+[...]
+# (optional) increase the maximum file upload size:
+upload_max_filesize = 100M
+```
 
-http {
-    [...]
-
-    index index.html index.php;
-
-    root        /home/john/web;
-    access_log  /var/log/nginx/access.log;
-    error_log   /var/log/nginx/error.log;
-
-    server {
-        listen       80;
-        server_name  localhost;
+To verify PHP settings currently set on the server, create a `phpinfo.php` in your webserver's document root
 
-        return 301 https://localhost$request_uri;
-    }
+```bash
+# example
+echo '<?php phpinfo(); ?>' | sudo tee /var/www/shaarli.mydomain.org/phpinfo.php
+#give read-only access to this file to the webserver user
+sudo chown www-data:root /var/www/shaarli.mydomain.org/phpinfo.php
+sudo chmod 0400 /var/www/shaarli.mydomain.org/phpinfo.php
+```
 
-    server {
-        listen       443 ssl;
-        server_name  localhost;
+Access the file from a web browser (eg. <https://shaarli.mydomain.org/phpinfo.php> and look at the _Loaded Configuration File_ and _Scan this dir for additional .ini files_ entries
 
-        ssl_certificate      /home/john/ssl/localhost.crt;
-        ssl_certificate_key  /home/john/ssl/localhost.key;
+It is recommended to remove the `phpinfo.php` when no longer needed as it publicly discloses details about your webserver configuration.
 
-        location /shaarli/ {
-            # Slim - rewrite URLs
-            try_files $uri /index.php$is_args$args;
 
-            access_log  /var/log/nginx/shaarli.access.log;
-            error_log   /var/log/nginx/shaarli.error.log;
-        }
+## Robots and crawlers
 
-        location = /shaarli/favicon.ico {
-            # serve the Shaarli favicon from its custom location
-            alias /var/www/shaarli/images/favicon.ico;
-        }
+To opt-out of indexing your Shaarli instance by search engines, create a `robots.txt` file at the root of your virtualhost:
 
-        include deny.conf;
-        include static_assets.conf;
-        include php.conf;
-    }
-}
+```
+User-agent: *
+Disallow: /
 ```
 
-## Proxies
-
-If Shaarli is served behind a proxy (i.e. there is a proxy server between clients and the web server hosting Shaarli), please refer to the proxy server documentation for proper configuration. In particular, you have to ensure that the following server variables are properly set:
+By default Shaarli already disallows indexing of your local copy of the documentation by default, using `<meta name="robots">` HTML tags. Your Shaarli instance may still be indexed by various robots on the public Internet, that do not respect this header or the robots standard.
 
-- `X-Forwarded-Proto`
-- `X-Forwarded-Host`
-- `X-Forwarded-For`
+- [Robots exclusion standard](https://en.wikipedia.org/wiki/Robots_exclusion_standard)
+- [Introduction to robots.txt](https://support.google.com/webmasters/answer/6062608?hl=en)
+- [Robots meta tag, data-nosnippet, and X-Robots-Tag specifications](https://developers.google.com/search/reference/robots_meta_tag)
+- [About robots.txt](http://www.robotstxt.org)
+- [About the robots META tag](https://www.robotstxt.org/meta.html)
 
-In you [Shaarli configuration](Shaarli-configuration) `data/config.json.php`, add the public IP of your proxy under `security.trusted_proxies`.
 
-See also [proxy-related](https://github.com/shaarli/Shaarli/issues?utf8=%E2%9C%93&q=label%3Aproxy+) issues.
+## Fail2ban
 
-## Robots and crawlers
+[fail2ban](http://www.fail2ban.org/wiki/index.php/Main_Page) is an intrusion prevention framework that reads server (Apache, SSH, etc.) and uses `iptables` profiles to block brute-force attempts. You need to create a filter to detect shaarli login failures in logs, and a jail configuation to configure the behavior when failed login attempts are detected:
 
-Shaarli disallows indexing and crawling of your local documentation pages by search engines, using `<meta name="robots">` HTML tags.
-Your Shaarli instance and other pages you host may still be indexed by various robots on the public Internet.
-You may want to setup a robots.txt file or other crawler control mechanism on your server.
-See [[1]](https://en.wikipedia.org/wiki/Robots_exclusion_standard), [[2]](https://support.google.com/webmasters/answer/6062608?hl=en) and [[3]](https://developers.google.com/search/reference/robots_meta_tag)
+```ini
+# /etc/fail2ban/filter.d/shaarli-auth.conf
+[INCLUDES]
+before = common.conf
+[Definition]
+failregex = \s-\s<HOST>\s-\sLogin failed for user.*$
+ignoreregex = 
+```
 
-## See also
+```ini
+# /etc/fail2ban/jail.local
+[shaarli-auth]
+enabled  = true
+port     = https,http
+filter   = shaarli-auth
+logpath  = /var/www/shaarli.mydomain.org/data/log.txt
+# allow 3 login attempts per IP address
+# (over a period specified by findtime = in /etc/fail2ban/jail.conf)
+maxretry = 3
+# permanently ban the IP address after reaching the limit
+bantime = -1
+```
 
- * [Server security](Server-security.md)
+Then restart the service: `sudo systemctl restart fail2ban`
 
-#### Webservers
 
-- [Apache/PHP - error log per VirtualHost](http://stackoverflow.com/q/176) (StackOverflow)
-- [Apache - PHP: php_value vs php_admin_value and the use of php_flag explained](https://ma.ttias.be/php-php_value-vs-php_admin_value-and-the-use-of-php_flag-explained/)
-- [Server-side TLS (Apache)](https://wiki.mozilla.org/Security/Server_Side_TLS#Apache) (Mozilla)
-- [Nginx Beginner's guide](http://nginx.org/en/docs/beginners_guide.html)
-- [Nginx ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)
-- [Nginx Pitfalls](http://wiki.nginx.org/Pitfalls)
-- [Nginx PHP configuration examples](http://kbeezie.com/nginx-configuration-examples/) (Karl Blessing)
-- [Server-side TLS (Nginx)](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) (Mozilla)
-- [How to Create Self-Signed SSL Certificates with OpenSSL](http://www.xenocafe.com/tutorials/linux/centos/openssl/self_signed_certificates/index.php)
-- [How do I create my own Certificate Authority?](https://workaround.org/certificate-authority)
-
-#### PHP
+## What next?
 
-- [Travis configuration](https://github.com/shaarli/Shaarli/blob/master/.travis.yml)
-- [PHP: Supported versions](http://php.net/supported-versions.php)
-- [PHP: Unsupported versions](http://php.net/eol.php) _(EOL - End Of Life)_
-- [PHP 7 Changelog](http://php.net/ChangeLog-7.php)
-- [PHP 5 Changelog](http://php.net/ChangeLog-5.php)
-- [PHP: Bugs](https://bugs.php.net/)
+[Shaarli installation](Installation.md)
diff --git a/doc/md/Server-security.md b/doc/md/Server-security.md
deleted file mode 100644 (file)
index ea1b637..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-## php.ini
-PHP settings are defined in:
-
-- a main configuration file, usually found under `/etc/php/$php_version/php.ini`; some distributions provide different configuration environments, e.g.
-    - `/etc/php/$php_version/cli/php.ini` - used when running console scripts
-    - `/etc/php/$php_version/apache2/php.ini` - used when a client requests PHP resources from Apache
-    - `/etc/php/$php_version/php-fpm.conf` - used when PHP requests are proxied to PHP-FPM
-- additional configuration files/entries, depending on the installed/enabled extensions:
-    - `/etc/php/conf.d/xdebug.ini`
-
-### Locate .ini files
-#### Console environment
-```bash
-$ php --ini
-Configuration File (php.ini) Path: /etc/php
-Loaded Configuration File:         /etc/php/php.ini
-Scan for additional .ini files in: /etc/php/conf.d
-Additional .ini files parsed:      /etc/php/conf.d/xdebug.ini
-```
-
-#### Server environment
-- create a `phpinfo.php` script located in a path supported by the web server, e.g.
-    - Apache (with user dirs enabled): `/home/myself/public_html/phpinfo.php`
-    - `/var/www/test/phpinfo.php`
-- make sure the script is readable by the web server user/group (usually, `www`, `www-data` or `httpd`)
-- access the script from a web browser
-- look at the _Loaded Configuration File_ and _Scan this dir for additional .ini files_ entries
-```php
-<?php phpinfo(); ?>
-```
-
-## fail2ban
-`fail2ban` is an intrusion prevention framework that reads server (Apache, SSH, etc.) and uses `iptables` profiles to block brute-force attempts:
-
-- [Official website](http://www.fail2ban.org/wiki/index.php/Main_Page)
-- [Source code](https://github.com/fail2ban/fail2ban)
-
-### Read Shaarli logs to ban IPs
-Example configuration:
-- allow 3 login attempts per IP address
-- after 3 failures, permanently ban the corresponding IP adddress
-
-`/etc/fail2ban/jail.local`
-```ini
-[shaarli-auth]
-enabled  = true
-port     = https,http
-filter   = shaarli-auth
-logpath  = /var/www/path/to/shaarli/data/log.txt
-maxretry = 3
-bantime = -1
-```
-
-`/etc/fail2ban/filter.d/shaarli-auth.conf`
-```ini
-[INCLUDES]
-before = common.conf
-[Definition]
-failregex = \s-\s<HOST>\s-\sLogin failed for user.*$
-ignoreregex = 
-```
-
-## Robots - Restricting search engines and web crawler traffic
-
-Creating a `robots.txt` with the following contents at the root of your Shaarli installation will prevent _honest_ web crawlers from indexing each and every link and Daily page from a Shaarli instance, thus getting rid of a certain amount of unsollicited network traffic.
-
-```
-User-agent: *
-Disallow: /
-```
-
-See:
-
-- http://www.robotstxt.org
-- http://www.robotstxt.org/robotstxt.html
-- http://www.robotstxt.org/meta.html
index 2462e20e51dba615ca4d2b0b71395640e2398db3..263fb7616014ebba6e2a4384d9e1741c21a93106 100644 (file)
-## Foreword
-
-**Do not edit configuration options in index.php! Your changes would be lost.** 
+# Shaarli configuration
 
 Once your Shaarli instance is installed, the file `data/config.json.php` is generated:
-* it contains all settings in JSON format, and can be edited to customize values
-* it defines which [plugins](Plugin-System) are enabled
-* its values override those defined in `index.php`
-* it is wrap in a PHP comment to prevent anyone accessing it, regardless of server configuration
-
-## File and directory permissions
-
-The server process running Shaarli must have:
-
-- `read` access to the following resources:
-    - PHP scripts: `index.php`, `application/*.php`, `plugins/*.php`
-    - 3rd party PHP and Javascript libraries: `inc/*.php`, `inc/*.js`
-    - static assets:
-        - CSS stylesheets: `inc/*.css`
-        - `images/*`
-    - RainTPL templates: `tpl/*.html`
-- `read`, `write` and `execution` access to the following directories:
-    - `cache` - thumbnail cache
-    - `data` - link data store, configuration options
-    - `pagecache` - Atom/RSS feed cache
-    - `tmp` - RainTPL page cache
-
-On a Linux distribution:
-
-- the web server user will likely be `www` or `http` (for Apache2)
-- it will be a member of a group of the same name: `www:www`, `http:http`
-- to give it access to Shaarli, either:
-    - unzip Shaarli in the default web server location (usually `/var/www/`) and set the web server user as the owner
-    - put users in the same group as the web server, and set the appropriate access rights
-- if you have a domain / subdomain to serve Shaarli, [configure the server](Server-configuration) accordingly
-
-## Configuration
-
-In `data/config.json.php`.
-
-See also [Plugin System](Plugin-System).
-
-### Credentials
-_These settings should not be edited_
-
-- **login**: Login username.  
-- **hash**: Generated password hash.  
-- **salt**: Password salt.
-
-### General
-
-- **title**: Shaarli's instance title.  
-- **header_link**: Link to the homepage.  
-- **links_per_page**: Number of shaares displayed per page.  
-- **timezone**: See [the list of supported timezones](http://php.net/manual/en/timezones.php).  
-- **enabled_plugins**: List of enabled plugins.
-- **default_note_title**: Default title of a new note.
-- **retrieve_description** (boolean): If set to true, for every new links Shaarli will try
-to retrieve the description and keywords from the HTML meta tags.
-
-### Security
-
-- **session_protection_disabled**: Disable session cookie hijacking protection (not recommended). 
-  It might be useful if your IP adress often changes.  
-- **ban_after**: Failed login attempts before being IP banned.  
-- **ban_duration**: IP ban duration in seconds.  
-- **open_shaarli**: Anyone can add a new link while logged out if enabled.  
-- **trusted_proxies**: List of trusted IP which won't be banned after failed login attemps. Useful if Shaarli is behind a reverse proxy.  
-- **allowed_protocols**: List of allowed protocols in shaare URLs or markdown-rendered descriptions. Useful if you want to store `javascript:` links (bookmarklets) in Shaarli (default: `["ftp", "ftps", "magnet"]`).
-
-### Resources
 
-- **data_dir**: Data directory.  
-- **datastore**: Shaarli's links database file path.  
-- **history**: Shaarli's operation history file path.
-- **updates**: File path for the ran updates file.  
-- **log**: Log file path.  
-- **update_check**: Last update check file path.  
-- **raintpl_tpl**: Templates directory.  
-- **raintpl_tmp**: Template engine cache directory.  
-- **thumbnails_cache**: Thumbnails cache directory.  
-- **page_cache**: Shaarli's internal cache directory.  
-- **ban_file**: Banned IP file path.
+- it contains all settings in JSON format, and can be edited to customize values
+- it defines which [plugins](Plugins.md) are enabled
+- its values override those defined in `index.php`
+- it is wrapped in a PHP comment so that its contents are never served by the web server, regardless of configuration
 
-### Translation
+**Do not edit configuration options in index.php! Your changes would be lost.**
 
-- **language**: translation language (also see [Translations](Translations))
-    - **auto** (default): The translation language is chosen from the browser locale. 
-    It means that the language can be different for 2 different visitors depending on their locale.  
-    - **en**: Use the English translation.
-    - **fr**: Use the French translation.
-- **mode**: 
-    - **auto** or **php** (default): Use the PHP implementation of gettext (slower)
-    - **gettext**: Use PHP builtin gettext extension 
-    (faster, but requires `php-gettext` to be installed and to reload the web server on update)
-- **extension**: Translation extensions for custom themes or plugins. 
-Must be an associative array: `translation domain => translation path`.
-
-### Updates
-
-- **check_updates**: Enable or disable update check to the git repository.  
-- **check_updates_branch**: Git branch used to check updates (e.g. `stable` or `master`).  
-- **check_updates_interval**: Look for new version every N seconds (default: every day).
+## Tools menu
 
-### Privacy
-
-- **default_private_links**: Check the private checkbox by default for every new link.  
-- **hide_public_links**: All links are hidden while logged out.  
-- **force_login**: if **hide_public_links** and this are set to `true`, all anonymous users are redirected to the login page.
-- **hide_timestamps**: Timestamps are hidden.
-- **remember_user_default**: Default state of the login page's *remember me* checkbox
-    - `true`: checked by default, `false`: unchecked by default
-
-### Feed
-
-- **rss_permalinks**: Enable this to redirect RSS links to Shaarli's permalinks instead of shaared URL.  
-- **show_atom**: Display ATOM feed button.
-
-### Thumbnail
+Some settings can be configured directly from a web browser by accesing the `Tools` menu. Values are read/written to/from the configuration file.
 
-- **enable_thumbnails**: Enable or disable thumbnail display.  
-- **enable_localcache**: Enable or disable local cache.
+![](https://i.imgur.com/boaaibC.png)
 
 ### LDAP
 
@@ -182,6 +75,9 @@ Must be an associative array: `translation domain => translation path`.
         "title": "My Shaarli",
         "header_link": "?"
     },
+    "dev": {
+        "debug": false,
+    }
     "extras": {
         "show_atom": false,
         "hide_public_links": false,
@@ -236,9 +132,90 @@ Must be an associative array: `translation domain => translation path`.
 } ?>
 ```
 
-## Additional configuration
+## Settings
+
+### Credentials
+
+_These settings should not be edited_
+
+- **login**: Login username.
+- **hash**: Generated password hash.
+- **salt**: Password salt.
+
+### General
+
+- **title**: Shaarli's instance title.
+- **header_link**: Link to the homepage.
+- **links_per_page**: Number of Shaares displayed per page.
+- **timezone**: See [the list of supported timezones](http://php.net/manual/en/timezones.php).
+- **enabled_plugins**: List of enabled plugins.
+- **default_note_title**: Default title of a new note.
+- **retrieve_description** (boolean): If set to true, for every new Shaare Shaarli will try to retrieve the description and keywords from the HTML meta tags.
+- **root_url**: Overrides automatic discovery of Shaarli instance's URL (e.g.) `https://sub.domain.tld/shaarli-folder/`.
+
+### Security
+
+- **session_protection_disabled**: Disable session cookie hijacking protection (not recommended).
+  It might be useful if your IP adress often changes.
+- **ban_after**: Failed login attempts before being IP banned.
+- **ban_duration**: IP ban duration in seconds.
+- **open_shaarli**: Anyone can add a new Shaare while logged out if enabled.
+- **trusted_proxies**: List of trusted IP which won't be banned after failed login attemps. Useful if Shaarli is behind a reverse proxy.
+- **allowed_protocols**: List of allowed protocols in shaare URLs or markdown-rendered descriptions. Useful if you want to store `javascript:` links (bookmarklets) in Shaarli (default: `["ftp", "ftps", "magnet"]`).
+
+### Resources
+
+- **data_dir**: Data directory.
+- **datastore**: Shaarli's Shaares database file path.
+- **history**: Shaarli's operation history file path.
+- **updates**: File path for the ran updates file.
+- **log**: Log file path.
+- **update_check**: Last update check file path.
+- **raintpl_tpl**: Templates directory.
+- **raintpl_tmp**: Template engine cache directory.
+- **thumbnails_cache**: Thumbnails cache directory.
+- **page_cache**: Shaarli's internal cache directory.
+- **ban_file**: Banned IP file path.
+
+### Translation
+
+- **language**: translation language (also see [Translations](Translations))
+    - **auto** (default): The translation language is chosen from the browser locale.
+    It means that the language can be different for 2 different visitors depending on their locale.
+    - **en**: Use the English translation.
+    - **fr**: Use the French translation.
+- **mode**:
+    - **auto** or **php** (default): Use the PHP implementation of gettext (slower)
+    - **gettext**: Use PHP builtin gettext extension
+    (faster, but requires `php-gettext` to be installed and to reload the web server on update)
+- **extension**: Translation extensions for custom themes or plugins.
+Must be an associative array: `translation domain => translation path`.
+
+### Updates
+
+- **check_updates**: Enable or disable update check to the git repository.
+- **check_updates_branch**: Git branch used to check updates (e.g. `stable` or `master`).
+- **check_updates_interval**: Look for new version every N seconds (default: every day).
+
+### Privacy
+
+- **default_private_links**: Check the private checkbox by default for every new Shaare.
+- **hide_public_links**: All Shaares are hidden while logged out.
+- **force_login**: if **hide_public_links** and this are set to `true`, all anonymous users are redirected to the login page.
+- **hide_timestamps**: Timestamps are hidden.
+- **remember_user_default**: Default state of the login page's *remember me* checkbox
+    - `true`: checked by default, `false`: unchecked by default
+
+### Feed
+
+- **rss_permalinks**: Enable this to redirect RSS links to Shaarli's permalinks instead of shaared URL.
+- **show_atom**: Display ATOM feed button.
+
+### Thumbnail
+
+- **enable_thumbnails**: Enable or disable thumbnail display.
+- **enable_localcache**: Enable or disable local cache.
 
-The `playvideos` plugin may require that you adapt your server's 
-[Content Security Policy](https://github.com/shaarli/Shaarli/blob/master/plugins/playvideos/README.md#troubleshooting) 
-configuration to work properly.
+## Plugins configuration
 
+See [Plugins](Plugins.md)
diff --git a/doc/md/Sharing-content.md b/doc/md/Sharing-content.md
deleted file mode 100644 (file)
index 9a16fc6..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-Content posted to Shaarli is separated in items called _Shaares_. For each Shaare,
-you can customize the following aspects:
-
- * URL to link to
- * Title
- * Free-text description
- * Tags
- * Public/private status
-
---------------------------------------------------------------------------------
-
-## Adding new Shaares
-
-While logged in to your Shaarli, you can add new Shaares in several ways:
-
- * [+Shaare button](#shaare-button)
- * [Bookmarklet](#bookmarklet)
- * Third-party [apps and browser addons](Community-&-Related-software.md#mobile-apps)
- * [REST API](https://shaarli.github.io/api-documentation/)
-
-### +Shaare button
-
- * While logged in to your Shaarli, click the **`+Shaare`** button located in the toolbar.
- * Enter the URL of a link you want to share.
- * Click `Add link`
- * The `New Shaare` dialog appears, allowing you to fill in the details of your Shaare.
-   * The Description, Title, and Tags will help you find your Shaare later using tags or full-text search.
-   * You can also check the “Private” box so that the link is saved but only visible to you (the logged-in user).
- * Click `Save`.
-
-<!-- TODO Add screenshot of add/edit link dialog -->
-
-### Bookmarklet
-
-The _Bookmarklet_ \[[1](https://en.wikipedia.org/wiki/Bookmarklet)\] is a special
-browser bookmark you can use to add new content to your Shaarli. This bookmarklet is
-compatible with Firefox, Opera, Chrome and Safari. To set it up:
-
- * Access the `Tools` page from the button in the toolbar.
- * Drag the **`✚Shaare link` button** to your browser's bookmarks bar.
-
-Once this is done, you can shaare any URL you are visiting simply by clicking the
-bookmarklet in your browser! The same `New Shaare` dialog as above is displayed.
-
-| Note | Websites which enforce Content Security Policy (CSP), such as github.com, disallow usage of bookmarklets. Unfortunately, there is nothing Shaarli can do about it. \[[1](https://github.com/shaarli/Shaarli/issues/196)]\ \[[2](https://bugzilla.mozilla.org/show_bug.cgi?id=866522)]\ \[[3](https://code.google.com/p/chromium/issues/detail?id=233903)]\ |
-|---------|---------|
-
-| Note | Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar. |
-|---------|---------|
-
-![](images/bookmarklet.png)
-
-
---------------------------------------------------------------------------------
-
-## Editing Shaares
-
-Any Shaare can edited by clicking its ![](images/edit_icon.png) `Edit` button.
-
-Editing a Shaare will not change it's permalink, each permalink always points to the
-latest revision of a Shaare.
-
---------------------------------------------------------------------------------
-
-## Using shaarli as a blog, notepad, pastebin...
-
-While adding or editing a link, leave the URL field blank to create a text-only
-("note") post. This allows you to post any kind of text content, such as blog
-articles, private or public notes, snippets... There is no character limit! You can
-access your Shaare from its permalink.
-
diff --git a/doc/md/Static-analysis.md b/doc/md/Static-analysis.md
deleted file mode 100644 (file)
index 29d9836..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-## WIP
-This topic is currently being discussed here:
-
-- [Fix coding style (static analysis)](https://github.com/shaarli/Shaarli/issues/95) (#95)
-- [Continuous Integration tools & features](https://github.com/shaarli/Shaarli/issues/130) (#130)
-
-### Usage
-Static analysis tools can be installed with Composer, and used through Shaarli's [Makefile](https://github.com/shaarli/Shaarli/blob/master/Makefile).
-
-For an overview of the available features, see:
-
-- [Code quality: Makefile to run static code checkers](https://github.com/shaarli/Shaarli/pull/124) (#124)
-- [Run PHPCS against different coding standards](https://github.com/shaarli/Shaarli/pull/276) (#276)
index 01fd9840dd5d18a3543c2b2284b102c92c4f7797..e1ed5e0006ce9368f1d3fb21cda23b62d4850c6f 100644 (file)
@@ -1,5 +1,8 @@
 # Troubleshooting
 
+First of all, ensure that both the [web server](Server-configuration.md) and [Shaarli](Shaarli-configuration.md) are correctly configured.
+
+
 ## Login
 
 ### I forgot my password!
@@ -8,38 +11,48 @@ Delete the file `data/config.json.php` and display the page again. You will be a
 
 ### I'm locked out - Login bruteforce protection
 
-Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse links.
+Login form is protected against brute force attacks: 4 failed logins will ban the IP address from login for 30 minutes. Banned IPs can still browse Shaares.
 
 - To remove the current IP bans, delete the file `data/ipbans.php`
 - To list all login attempts, see `data/log.txt` (succesful/failed logins, bans/lifted bans)
 
+--------------------------------------
+
 ## Browser issues
 
 ### Redirection issues (HTTP Referer)
 
-Depending on its configuration and installed plugins, the browser may remove or alter (spoof) [HTTP referers](https://en.wikipedia.org/wiki/HTTP_referer), thus preventing Shaarli from properly redirecting between pages. Referer settings are available by browsing `about:config` and are documented [here](https://wiki.mozilla.org/Security/Referrer). `network.http.referer.spoofSource = true` in particular is known to break some functionality in Shaarli.
+Shaarli relies on `HTTP_REFERER` for some functions (like redirects and clicking on tags). If you have disabled or altered/spoofed [HTTP referers](https://en.wikipedia.org/wiki/HTTP_referer) in your browser, some features of Shaarli may not work as expected (depending on configuration and installed plugins), notably redirections between pages.
+
+Firefox Referer settings are available by browsing `about:config` and are documented [here](https://wiki.mozilla.org/Security/Referrer). `network.http.referer.spoofSource = true` in particular is known to break some functionality in Shaarli.
+
 
 ### Firefox, localhost and redirections
 
 `localhost` is not a proper Fully Qualified Domain Name (FQDN); if Firefox has been set up to spoof referers, or only accept requests from the same base domain/host,
 Shaarli redirections will not work properly. To solve this, assign a local domain to your host, e.g. `localhost.lan` in your [hosts file](https://en.wikipedia.org/wiki/Hosts_(file)) and browse Shaarli at http://localhost.lan/.
 
+-----------------------------------------
+
 ## Hosting problems
 
 ### Old PHP versions
 
-On **free.fr**: free.fr now supports php 5.6.x([link](http://les.pages.perso.chez.free.fr/migrations/php5v6.io))
-and so support now the tag autocompletion but you have to do the following.
-
-At the root of your webspace create a `sessions` directory and a `.htaccess` file containing:
+- On hosts (such as **free.fr**) which only support PHP 5.6, Shaarli [v0.10.4](https://github.com/shaarli/Shaarli/releases/tag/v0.10.4) is the maximum supported version. At the root of your webspace create a `sessions` directory and a `.htaccess` file containing:
 
 ```xml
 <IfDefine Free>
 php56 1
 </IfDefine>
+<Files ".ht*">
+Order allow,deny
+Deny from all
+Satisfy all
+</Files>
+Options -Indexes
 ```
 
-- If you have an error such as: `Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx`, it means that your host is using php4, not php5. Shaarli requires php 5.1. Try changing the file extension to `.php5`
+- If you have an error such as: `Parse error: syntax error, unexpected '=', expecting '(' in /links/index.php on line xxx`, it means that your host is using PHP 4, not PHP 5. Shaarli requires PHP 5.1. Try changing the file extension to `.php5`
 - On **1and1** : If you add the link from the page (and not from the bookmarklet), Shaarli will no be able to get the title of the page. You will have to enter it manually. (Because they have disabled the ability to download a file through HTTP).
 - If you have the error `Warning: file_get_contents() [function.file-get-contents]: URL file-access is disabled in the server configuration in /…/index.php on line xxx`, it means that your host has disabled the ability to fetch a file by HTTP in the php config (Typically in 1and1 hosting). Bad host. Change host. Or comment the following lines:
 
@@ -49,9 +62,11 @@ php56 1
 //if (strpos($status,'200 OK')) $title=html_extract_title($data);
 ```
 
-- On hosts which forbid outgoing HTTP requests (such as free.fr), some thumbnails will not work.
+- On hosts (such as **free.fr**) which forbid outgoing HTTP requests, some thumbnails will not work.
+- On hosts (such as **free.fr**) which limit the number of FTP connections, setup your FTP client accordingly (else some files may be missing after upload).
 - On **lost-oasis**, RSS doesn't work correctly, because of this message at the begining of the RSS/ATOM feed : `<? // tout ce qui est charge ici (generalement des includes et require) est charge en permanence. ?>`. To fix this, remove this message from `php-include/prepend.php`
 
+
 ### Dates are not properly formatted
 
 Shaarli tries to sniff the language of the browser (using `HTTP_ACCEPT_LANGUAGE` headers)
@@ -71,11 +86,118 @@ This can be caused by several things:
 - You may be using OperaTurbo or OperaMini, which use their own proxies which may change from time to time.
 - If you have another application on the same webserver where Shaarli is installed, these application may forcefully expire php sessions.
 
+
 ### Old apache versions, Internal Server Error
 
 If you hosting provider only provides apache 2.2 and no support for `mod_version`, `.htaccess` files may cause 500 errors (Internal Server Error). See [this workaround](https://github.com/shaarli/Shaarli/issues/1196#issuecomment-412271085).
 
-## Sessions do not seem to work correctly on your server
+
+### Sessions do not seem to work correctly on your server
 
 Follow the instructions in the error message. Make sure you are accessing shaarli via a direct IP address or a proper hostname. If you have **no dots** in the hostname (e.g. `localhost` or `http://my-webserver/shaarli/`), some browsers will not store cookies at all (this respects the [HTTP cookie specification](http://curl.haxx.se/rfc/cookie_spec.html)).
 
+----------------------------------------------------------
+
+## Upgrades
+
+### You must specify an integer as a key
+
+In `v0.8.1` we changed how Shaare keys are handled (from timestamps to incremental integers). Take a look at `data/updates.txt` content.
+
+
+### `updates.txt` contains `updateMethodDatastoreIds`
+
+Try to delete it and refresh your page while being logged in.
+
+### `updates.txt` doesn't exist or doesn't contain `updateMethodDatastoreIds`
+
+1. Create `data/updates.txt` if it doesn't exist
+2. Paste this string in the update file `;updateMethodRenameDashTags;`
+3. Login to Shaarli
+4. Delete the update file
+5. Refresh
+
+
+
+--------------------------------------------------------
+
+## Import/export
+
+### Importing shaarli data to Firefox
+
+- In Firefox, open the bookmark manager (`Bookmarks menu > Show all bookmarks` or `Ctrl+Shift+B`), select `Import and Backup > Import bookmarks in HTML format`
+- Make sure the `Prepend note permalinks with this Shaarli instance's URL` box is checked when exporting, so that text-only/notes Shaares still point to the Shaarli instance you exported them from.
+- Depending on the number of bookmarks, the import can take some time.
+
+You may be interested in these Firefox addons to manage bookmarks imported from Shaarli
+
+- [Bookmark Deduplicator](https://addons.mozilla.org/en-US/firefox/addon/bookmark-deduplicator/) - provides an easy way to deduplicate your bookmarks
+- [TagSieve](https://addons.mozilla.org/en-US/firefox/addon/tagsieve/) - browse your bookmarks by their tags
+
+### Diigo
+
+If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.)
+
+### Mister Wong
+
+See [this issue](https://github.com/sebsauvage/Shaarli/issues/146) for import tweaks.
+
+### SemanticScuttle
+
+To correctly import the tags from a [SemanticScuttle](http://semanticscuttle.sourceforge.net/) HTML export, edit the HTML file before importing and replace all occurences of `tags=` (lowercase) to `TAGS=` (uppercase).
+
+### Scuttle
+
+Shaarli cannot import data directly from [Scuttle](https://github.com/scronide/scuttle).
+
+However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli)
+tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer.
+
+### Refind.com
+
+You can use the third-party tool [Derefind](https://github.com/ShawnPConroy/Derefind) to convert refind.com bookmark exports to a format that can be imported into Shaarli.
+
+
+-------------------------------------------------------
+
+## Other
+
+### The bookmarklet doesn't work
+
+Websites which enforce Content Security Policy (CSP), such as github.com, disallow usage of bookmarklets. Unfortunately, there is nothing Shaarli can do about it ([1](https://github.com/shaarli/Shaarli/issues/196), [2](https://bugzilla.mozilla.org/show_bug.cgi?id=866522), [3](https://code.google.com/p/chromium/issues/detail?id=233903).
+
+Under Opera, you can't drag'n drop the button: You have to right-click on it and add a bookmark to your personal toolbar.
+
+
+### Changing the timestamp for a shaare
+
+- Look for `<input type="hidden" name="lf_linkdate" value="{$link.linkdate}">` in `tpl/editlink.tpl` (line 14)
+- Replace `type="hidden"` with `type="text"` from this line
+- A new date/time field becomes available in the edit/new Shaare dialog.
+- You can set the timestamp manually by entering it in the format `YYYMMDD_HHMMS`.
+
+### Clearing Shaarli caches
+
+For debugging purposes:
+
+```bash
+# clear raintpl cache and temporary files
+find /var/www/links/cache/ /var/www/links/pagecache/ /var/www/links/tmp/ -type f -exec rm -v '{}' \;
+# if you have a php accelerator such as php-apcu, restart the webserver
+sudo systemctl restart apache2
+```
+
+-------------------------------------------------------
+
+## Support
+
+If the solutions above did not help, please:
+
+- Come and ask question on the [Gitter chat](https://gitter.im/shaarli/Shaarli) (also reachable via [IRC](https://irc.gitter.im/))
+- Search for [issues](https://github.com/shaarli/Shaarli/issues) and [Pull Requests](https://github.com/shaarli/Shaarli/pulls)
+    - if you find one that is related to the issue, feel free to comment and provide additional details (host/Shaarli setup...)
+    - check issues labeled [`feature`](https://github.com/shaarli/Shaarli/labels/feature), [`enhancement`](https://github.com/shaarli/Shaarli/labels/enhancement), and [`plugin`](https://github.com/shaarli/Shaarli/labels/plugin) if you would like a feature added to Shaarli.
+    - else, [open a new issue](https://github.com/shaarli/Shaarli/issues/new), and provide information about the problem:
+        - _what happens?_ - display glitches, invalid data, security flaws...
+        - _what is your configuration?_  - OS, server version, activated extensions, web browser...
+        - _is it reproducible?_
\ No newline at end of file
diff --git a/doc/md/Unit-tests.md b/doc/md/Unit-tests.md
deleted file mode 100644 (file)
index a954465..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-The testing framework used is [PHPUnit](https://phpunit.de/); it can be installed with [Composer](https://getcomposer.org/), which is a dependency management tool.
-
-## Setup a testing environment
-
-### Install composer
-
-You can either use:
-
-- a system-wide version, e.g. installed through your distro's package manager (eg. `sudo apt install composer`)
-- a local version, downloadable [here](https://getcomposer.org/download/). To update a local composer installation, run `php composer.phar self-update`
-
-
-### Install Shaarli development dependencies
-
-```bash
-$ cd /path/to/shaarli
-$ composer install
-```
-
-### Install Xdebug
-
-Xdebug must be installed and enable for PHPUnit to generate coverage reports. See http://xdebug.org/docs/install.
-
-```bash
-# for Debian-based distributions
-$ aptitude install php-xdebug
-
-# for ArchLinux:
-$ pacman -S xdebug
-```
-
-Then add the following line to `/etc/php/<PHP_VERSION>/cli/php.ini`:
-
-```ini
-zend_extension=xdebug.so
-```
-
-## Run unit tests
-
-Run `make test` and ensure tests return `OK`. If tests return failures, refer to PHPUnit messages and fix your code/tests accordingly.
-
-By default, PHPUnit will run all suitable tests found under the `tests` directory. Each test has 3 possible outcomes:
-
-- `.` - success
-- `F` - failure: the test was run but its results are invalid
-    - the code does not behave as expected
-    - dependencies to external elements: globals, session, cache...
-- `E` - error: something went wrong and the tested code has crashed
-    - typos in the code, or in the test code
-    - dependencies to missing external elements
-
-If Xdebug has been installed and activated, two coverage reports will be generated:
-
-- a summary in the console
-- a detailed HTML report with metrics for tested code
-    - to open it in a web browser: `firefox coverage/index.html &`
-
-### Executing specific tests
-
-Add a [`@group`](https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group) annotation in a test class or method comment:
-
-```php
-/**
- * Netscape bookmark import
- * @group WIP
- */
-class BookmarkImportTest extends PHPUnit_Framework_TestCase
-{
-   [...]
-}
-```
-
-To run all tests annotated with `@group WIP`:
-```bash
-$ vendor/bin/phpunit --group WIP tests/
-```
-
-### Running tests inside Docker containers
-
-Test Dockerfiles are located under `tests/docker/<distribution>/Dockerfile`,
-and can be used to build Docker images to run Shaarli test suites under common
-Linux environments.
-
-Dockerfiles are provided for the following environments:
-
-- `alpine36` - [Alpine 3.6](https://www.alpinelinux.org/downloads/)
-- `debian8` - [Debian 8 Jessie](https://www.debian.org/DebianJessie) (oldstable)
-- `debian9` - [Debian 9 Stretch](https://wiki.debian.org/DebianStretch) (stable)
-- `ubuntu16` - [Ubuntu 16.04 Xenial Xerus](http://releases.ubuntu.com/16.04/) (LTS)
-
-What's behind the curtains:
-
-- each image provides:
-    - a base Linux OS
-    - Shaarli PHP dependencies (OS packages)
-    - test PHP dependencies (OS packages)
-    - Composer
-- the local workspace is mapped to the container's `/shaarli/` directory,
-- the files are rsync'd so tests are run using a standard Linux user account
-  (running tests as `root` would bypass permission checks and may hide issues)
-- the tests are run inside the container.
-
-To run tests inside a Docker container:
-
-```bash
-# build the Debian 9 Docker image for unit tests
-$ cd /path/to/shaarli
-$ cd tests/docker/debian9
-$ docker build -t shaarli-test:debian9 .
-
-# install/update 3rd-party test dependencies
-$ composer install --prefer-dist
-
-# run tests using the freshly built image
-$ docker run -v $PWD:/shaarli shaarli-test:debian9 docker_test
-
-# run the full test campaign
-$ docker run -v $PWD:/shaarli shaarli-test:debian9 docker_all_tests
-```
index d5682a340dd35d650e8ed025ca4d5e75e666ba99..bfef3e8c1059a8ce137ba53665e3ae830de1709a 100644 (file)
@@ -1,96 +1,83 @@
-## Preparation
+# Upgrade and migration
 
-### Note your current version
+## Note your current version
 
 If anything goes wrong, it's important for us to know which version you're upgrading from.
 The current version is present in the `shaarli_version.php` file.
 
-### Backup your data
 
-Shaarli stores all user data under the `data` directory:
+## Backup your data
 
-- `data/config.json.php` (or `data/config.php` for older Shaarli versions) - main configuration file
-- `data/datastore.php` - bookmarked links
-- `data/ipbans.php` - banned IP addresses
-- `data/updates.txt` - contains all automatic update to the configuration and datastore files already run
+Shaarli stores all user data and [configuration](Shaarli-configuration.md) under the `data` directory. [Backup](Backup-and-restore.md) this repository _before_ upgrading Shaarli. You will need to restore it after the following upgrade steps.
 
-See [Shaarli configuration](Shaarli-configuration) for more information about Shaarli resources.
-
-It is recommended to backup this repository _before_ starting updating/upgrading Shaarli:
-
-- users with SSH access: copy or archive the directory to a temporary location
-- users with FTP access: download a local copy of your Shaarli installation using your favourite client
+```bash
+sudo cp -r /var/www/shaarli.mydomain.org/data ~/shaarli-data-backup
+```
 
-### Migrating data from a previous installation
+## Upgrading from ZIP archives
 
-As all user data is kept under `data`, this is the only directory you need to worry about when migrating to a new installation, which corresponds to the following steps:
+If you installed Shaarli from a [release ZIP archive](Installation.md#from-release-zip):
 
-- backup the `data` directory
-- install or update Shaarli:
-    - fresh installation - see [Download and Installation](Download-and-Installation)
-    - update - see the following sections
-- check or restore the `data` directory
+```bash
+# Download the archive to the server, and extract it
+cd ~
+wget https://github.com/shaarli/Shaarli/releases/download/v0.X.Y/shaarli-v0.X.Y-full.zip
+unzip shaarli-v0.X.Y-full.zip
 
-## Recommended : Upgrading from release archives
+# overwrite your Shaarli installation with the new release **All data will be lost, see _Backup your data_ above.**
+sudo rsync -avP --delete Shaarli/ /var/www/shaarli.mydomain.org/
 
-All tagged revisions can be downloaded as tarballs or ZIP archives from the [releases](https://github.com/shaarli/Shaarli/releases) page.
+# restore file permissions as described on the installation page
+sudo chown -R root:www-data /var/www/shaarli.mydomain.org
+sudo chmod -R g+rX /var/www/shaarli.mydomain.org
+sudo chmod -R g+rwX /var/www/shaarli.mydomain.org/{cache/,data/,pagecache/,tmp/}
 
-We recommend that you use the latest release tarball with the `-full` suffix. It contains the dependencies, please read [Download and Installation](Download-and-Installation) for `git` complete instructions.
+# restore backups of the data directory
+sudo cp -r ~/shaarli-data-backup/* /var/www/shaarli.mydomain.org/data/
 
-Once downloaded, extract the archive locally and update your remote installation (e.g. via FTP) -be sure you keep the content of the `data` directory!
+# If you use gettext mode for translations (not the default), reload your web server.
+sudo systemctl restart apache2
+sudo systemctl restart nginx
+```
 
-If you use translations in gettext mode - meaning you manually changed the default mode -,
-reload your web server.
+If you don't have shell access (eg. on shared hosting), backup the shaarli data directory, download the ZIP archive locally, extract it, upload it to the server using file transfer, and restore the data directory backup.
 
-After upgrading, access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli configuration) for more details).
+Access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli-configuration.md) for more details).
 
-## Upgrading with Git
 
-### Updating a community Shaarli
+## Upgrading from Git
 
-If you have installed Shaarli from the [community Git repository](Download#clone-with-git-recommended), simply [pull new changes](https://www.git-scm.com/docs/git-pull) from your local clone:
+If you have installed Shaarli [from sources](Installation.md#from-sources):
 
 ```bash
-$ cd /path/to/shaarli
-$ git pull
-
-From github.com:shaarli/Shaarli
- * branch            master     -> FETCH_HEAD
-Updating ebd67c6..521f0e6
-Fast-forward
- application/Url.php   | 1 +
- shaarli_version.php   | 2 +-
- tests/Url/UrlTest.php | 1 +
- 3 files changed, 3 insertions(+), 1 deletion(-)
-```
+# pull new changes from your local clone
+cd /var/www/shaarli.mydomain.org/
+sudo git pull
 
-Shaarli >= `v0.8.x`: install/update third-party PHP dependencies using [Composer](https://getcomposer.org/):
+# update PHP dependencies (Shaarli >= v0.8)
+sudo composer install --no-dev
 
-```bash
-$ composer install --no-dev
+# update translations (Shaarli >= v0.9.2)
+sudo make translate
 
-Loading composer repositories with package information
-Updating dependencies
-  - Installing shaarli/netscape-bookmark-parser (v1.0.1)
-    Downloading: 100%
-```
+# If you use translations in gettext mode (not the default), reload your web server.
+sudo systemctl reload apache
+sudo systemctl reload nginx
 
-Shaarli >= `v0.9.2` supports translations:
+# update front-end dependencies (Shaarli >= v0.10.0)
+sudo make build_frontend
 
-```bash
-$ make translate
-```
+# restore file permissions as described on the installation page
+sudo chown -R root:www-data /var/www/shaarli.mydomain.org
+sudo chmod -R g+rX /var/www/shaarli.mydomain.org
+sudo chmod -R g+rwX /var/www/shaarli.mydomain.org/{cache/,data/,pagecache/,tmp/}
+``` 
 
-If you use translations in gettext mode, reload your web server.
+Access your fresh Shaarli installation from a web browser; the configuration and data store will then be automatically updated, and new settings added to `data/config.json.php` (see [Shaarli configuration](Shaarli-configuration.md) for more details).
 
-Shaarli >= `v0.10.0` manages its front-end dependencies with nodejs. You need to install 
-[yarn](https://yarnpkg.com/lang/en/docs/install/):
+---------------------------------------------------------------
 
-```bash
-$ make build_frontend
-``` 
-
-### Migrating and upgrading from Sebsauvage's repository
+## Migrating and upgrading from Sebsauvage's repository
 
 If you have installed Shaarli from [Sebsauvage's original Git repository](https://github.com/sebsauvage/Shaarli), you can use [Git remotes](https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes) to update your working copy.
 
@@ -104,7 +91,7 @@ The following guide assumes that:
     - no versioned file has been locally modified
     - no untracked files are present
 
-#### Step 0: show repository information
+### Step 0: show repository information
 
 ```bash
 $ cd /path/to/shaarli
@@ -122,7 +109,7 @@ Your branch is up-to-date with 'origin/master'.
 nothing to commit, working directory clean
 ```
 
-#### Step 1: update Git remotes
+### Step 1: update Git remotes
 
 ```
 $ git remote rename origin sebsauvage
@@ -146,7 +133,7 @@ From https://github.com/shaarli/Shaarli
  * [new tag]         v0.7.0     -> v0.7.0
 ```
 
-#### Step 2: use the stable community branch
+### Step 2: use the stable community branch
 
 ```bash
 $ git checkout origin/stable -b stable
@@ -177,8 +164,7 @@ $ make translate
 
 If you use translations in gettext mode, reload your web server.
 
-Shaarli >= `v0.10.0` manages its front-end dependencies with nodejs. You need to install 
-[yarn](https://yarnpkg.com/lang/en/docs/install/):
+Shaarli >= `v0.10.0` manages its front-end dependencies with nodejs. You need to install [yarn](https://yarnpkg.com/lang/en/docs/install/):
 
 ```bash
 $ make build_frontend
@@ -204,30 +190,14 @@ Writing objects: 100% (3317/3317), done.
 Total 3317 (delta 2050), reused 3301 (delta 2034)to
 ```
 
-#### Step 3: configuration
+### Step 3: configuration
 
 After migrating, access your fresh Shaarli installation from a web browser; the
 configuration will then be automatically updated, and new settings added to
-`data/config.json.php` (see [Shaarli configuration](Shaarli-configuration) for more
+`data/config.json.php` (see [Shaarli configuration](Shaarli-configuration.md) for more
 details).
 
 ## Troubleshooting
 
-If the solutions provided here don't work, please open an issue specifying which version you're upgrading from and to.
-
-### You must specify an integer as a key
-
-In `v0.8.1` we changed how link keys are handled (from timestamps to incremental integers).
-Take a look at `data/updates.txt` content.
-
-#### `updates.txt` contains `updateMethodDatastoreIds`
-
-Try to delete it and refresh your page while being logged in.
-
-#### `updates.txt` doesn't exist or doesn't contain `updateMethodDatastoreIds`
+If the solutions provided here don't work, see [Troubleshooting](Troubleshooting.md) and/or open an issue specifying which version you're upgrading from and to.
 
-1. Create `data/updates.txt` if it doesn't exist
-2. Paste this string in the update file `;updateMethodRenameDashTags;`
-3. Login to Shaarli
-4. Delete the update file
-5. Refresh
diff --git a/doc/md/Usage.md b/doc/md/Usage.md
new file mode 100644 (file)
index 0000000..6dadde0
--- /dev/null
@@ -0,0 +1,111 @@
+## Features
+
+For any item posted to Shaarli (called a _Shaare_), you can customize the following aspects:
+
+- URL to link to
+- Title
+- Free-text description
+- Tags
+- Public/private status
+
+
+### Adding/editing Shaares
+
+While logged in to your Shaarli, you can add, edit or delete Shaares:
+
+- Using the **+Shaare** button: enter the URL you want to share, click `Add link`, fill in the details of your Shaare, and `Save`
+- Using the [Bookmarklet](https://en.wikipedia.org/wiki/Bookmarklet): drag the `✚Shaare link` button from the `Tools` page to your browser's bookmarks bar, click it to share the current page.
+- Using [apps and browser addons](Community-and-related-software.md#mobile-apps)
+- Using the [REST API](https://shaarli.github.io/api-documentation/)
+- Any Shaare can edited by clicking its ![](images/edit_icon.png) `Edit` button.
+
+
+### Tags
+
+Tags can be be used to organize and categorize your Shaares:
+
+- You can rename, merge and delete tags from the _Tools_ menu or the [tag cloud/list](#tag-cloud)
+- Tags are auto-completed (from the list of existing tags) in all dialogs
+- Tags can be combined with text in [search](#search) queries
+
+
+### Public/private Shaares
+
+Additional filter buttons can be found at the top left of the Shaare list **only when logged in**:
+
+- **Only show private Shaares:** Private shares can be searched by clicking the `only show private links` toggle button top left of the Shaares list (only when logged in)
+
+
+### Permalinks
+
+Permalinks are fixed, short links attached to each Shaare. Editing a Shaare will not change it's permalink, each permalink always points to the latest revision of a Shaare.
+
+
+### Text-only (note) Shaares
+
+Shaarli can be used as a minimal blog, notepad, pastebin...: While adding or editing a Shaare, leave the URL field blank to create a text-only ("note") post. This allows you to post any kind of text content, such as blog articles, private or public notes, snippets... There is no character limit! You can access your post from its permalink.
+
+
+### Search
+
+- **Plain text search:** Use `Search text` to search in all fields of all Shaares (Title, URL, Description...). Use double-quotes (example `"exact search"`) to search for the exact expression.
+- **Tags search:** `Filter by tags` allow only displaying Shaares tagged with one or multiple tags (use space to separate tags).
+- **Hidden tags:** tags starting with a dot `.` (example `.secret`) are private. They can only be seen and searched when logged in.
+- **Exclude text/tags:** Use the `-` operator before a word or tag to exclude Shaares matching this word from search results (`NOT` operator).
+- **Untagged links:** Shaares without tags can be searched by clicking the `untagged` toggle button top left of the Shaares list (only when logged in).
+
+Both exclude patterns and exact searches can be combined with normal searches (example `"exact search" term otherterm -notthis "very exact" stuff -notagain`). Only AND (and NOT) search is currrently supported.
+
+Active search terms are displayed on top of the link list. To remove terms/tags from the curent search, click the `x` next to any of them, or simply clear text/tag search fields.
+
+
+### Tag cloud
+
+The `Tag cloud` page diplays a "cloud" or list view of all tags in your Shaarli (most frequently used tags are displayed with a bigger font size)
+
+
+- **Tags list:** click on `Most used` or `Alphabetical` to display tags as a list. You can also edit/delete tags for this page.
+- Click on any tag to search all Shaares matching this tag.
+- **Filtering the tag cloud/list:** Click on the counter next to a tag to show other tags of Shaares with this tag. Repeat this any number of times to further filter the tag cloud. Click `List all links with those tags` to display Shaares matching your current tag filter set.
+
+
+
+### RSS feeds
+
+RSS/ATOM feeds feeds are available (in ATOM with `/feed/atom` and RSS with `/feed/rss`)
+
+- **Filtering RSS feeds:** RSS feeds and picture wall can also be restricted to only return items matching a text/tag search. For example, search for `photography` (text or tags) in Shaarli, then click the `RSS Feed` button. A feed with only matching results is displayed.
+- Add the `&nb` parameter in feed URLs to specify the number of Shaares you want in a feed (default if not specified: `50`). The keyword `all` is available if you want everything.
+- Add the `&permalinks` parameter in feed URLs to point permalinks to the corresponding shaarly entry/link instead of the direct, Shaare URL attribute
+
+![](images/rss-filter-1.png) ![](images/rss-filter-2.png)
+
+```bash
+# examples
+https://shaarli.mydomain.org/feed/atom?permalinks
+https://shaarli.mydomain.org/feed/atom?permalinks&nb=42
+https://shaarli.mydomain.org/feed/atom?permalinks&nb=all
+https://shaarli.mydomain.org/feed/rss?searchtags=nature
+https://shaarli.mydomain.org/links/picture-wall?searchterm=poney
+```
+
+
+### Picture wall
+
+- The picture wall can be filtered by text or tags search in the same way as [RSS feeds](#rss-feeds)
+
+
+### Import/export
+
+To **export Shaares as a HTML file**, under _Tools > Export_, choose:
+
+- `Export all` to export both public and private Shaares
+- `Export public` to export public Shaares only
+- `Export private` to export private Shaares only
+
+Restore by using the `Import` feature.
+
+- These exports contain the full data (URL, title, tags, date, description, public/private status of your Shaares)
+- They can also be imported to your web browser bookmarks.
+
+To **import a HTML bookmarks file** exported from your browser, just use the `Import` feature. For each "folder" in the bookmarks you imported, a new tag will be created (for example a bookmark in `Movies > Sci-fi` folder will be tagged `Movies` `Sci-fi`).
diff --git a/doc/md/dev/Development.md b/doc/md/dev/Development.md
new file mode 100644 (file)
index 0000000..5c085e0
--- /dev/null
@@ -0,0 +1,179 @@
+# Development
+
+Please read [Contributing to Shaarli](https://github.com/shaarli/Shaarli/tree/master/CONTRIBUTING.md)
+
+## Guidelines
+
+
+- [Unit tests](Unit-tests)
+- Javascript linting - Shaarli uses [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript). 
+Run `make eslint` to check JS style.
+- [GnuPG signature](GnuPG-signature) for tags/releases
+
+
+## Third-party libraries
+
+CSS:
+
+- Yahoo UI [CSS Reset](http://yuilibrary.com/yui/docs/cssreset/) - standardize cross-browser rendering
+
+Javascript:
+
+- [Awesomeplete](https://leaverou.github.io/awesomplete/) ([GitHub](https://github.com/LeaVerou/awesomplete)) - autocompletion in input forms
+- [bLazy](http://dinbror.dk/blazy/) ([GitHub](https://github.com/dinbror/blazy)) - lazy loading for thumbnails
+- [qr.js](http://neocotic.com/qr.js/) ([GitHub](https://github.com/neocotic/qr.js)) - QR code generation
+
+PHP (managed through [`composer.json`](https://github.com/shaarli/Shaarli/blob/master/composer.json)):
+
+- [RainTPL](https://github.com/rainphp/raintpl) - HTML templating for PHP
+- [`shaarli/netscape-bookmark-parser`](https://packagist.org/packages/shaarli/netscape-bookmark-parser) - Import bookmarks from Netscape files
+- [`erusev/parsedown`](https://packagist.org/packages/erusev/parsedown) - Parse MarkDown syntax for the MarkDown plugin
+- [`slim/slim`](https://packagist.org/packages/slim/slim) - Handle routes and middleware for the REST API
+- [`ArthurHoaro/web-thumbnailer`](https://github.com/ArthurHoaro/web-thumbnailer) - PHP library which will retrieve a thumbnail for any given URL
+- [`pubsubhubbub/publisher`](https://github.com/pubsubhubbub/php-publisher) - A PubSubHubbub publisher module for PHP.
+- [`gettext/gettext`](https://github.com/php-gettext/Gettext) - PHP library to collect and manipulate gettext (.po, .mo, .php, .json, etc)
+
+
+## Security
+
+- The password is salted, hashed and stored in the data subdirectory, in a PHP file, and protected by htaccess. Even if the webserver does not support htaccess, the hash is not readable by URL. Even if the .php file is stolen, the password cannot deduced from the hash. The salt prevents rainbow-tables attacks.
+- Directories are protected using `.htaccess` files
+- Forms are protected against [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery):
+    - Forms which act on data (save,delete…) contain a token generated by the server.
+    - Any posted form which does not contain a valid token is rejected.
+    - Any token can only be used once.
+    - Tokens are attached to the session and cannot be reused in another session.
+- Sessions automatically expire after 60 minutes.
+- Sessions are protected against hijacking: the session ID cannot be used from a different IP address.
+- Links are stored as an associative array which is serialized, compressed (with deflate), base64-encoded and saved as a comment in a `.php` file - even if the server does not support `.htaccess` files, the data file will still not be readable by URL.
+- Bruteforce protection: Successful and failed login attempts are logged - IP bans are enforced after a configurable amount of failures. Logs can also be used consumed by [fail2ban](../Server-configuration.md#fail2ban)
+- A pop-up notification is shown when a new release is available.
+
+## Link structure
+
+Every link available through the `LinkDB` object is represented as an array 
+containing the following fields:
+
+  * `id` (integer): Unique identifier.
+  * `title` (string): Title of the link.
+  * `url` (string): URL of the link. Used for displayable links (without redirector, url encoding, etc.).  
+           Can be absolute or relative for Notes.
+  * `real_url` (string): Real destination URL, can be redirected, encoded, etc.
+  * `shorturl` (string): Permalink small hash.
+  * `description` (string): Link text description.
+  * `private` (boolean): whether the link is private or not.
+  * `tags` (string): all link tags separated by a single space
+  * `thumbnail` (string|boolean): relative path of the thumbnail cache file, or false if there isn't any.
+  * `created` (DateTime): link creation date time.
+  * `updated` (DateTime): last modification date time.
+  
+Small hashes are used to make a link to an entry in Shaarli. They are unique: the date of the item (eg. `20110923_150523`) is hashed with CRC32, then converted to base64 and some characters are replaced. They are always 6 characters longs and use only `A-Z a-z 0-9 - _` and `@`.
+
+
+## Directory structure
+
+Here is the directory structure of Shaarli and the purpose of the different files:
+
+```bash
+       index.php        # Main program
+       application/     # Shaarli classes
+               ├── LinkDB.php
+
+        ...
+
+               └── Utils.php
+       tests/           # Shaarli unitary & functional tests
+               ├── LinkDBTest.php
+
+        ...
+
+               ├── utils    # utilities to ease testing
+               │   └── ReferenceLinkDB.php
+               └── UtilsTest.php
+       assets/
+           ├── common/                # Assets shared by multiple themes
+               ├── ...
+        ├── default/               # Assets for the default template, before compilation
+            ├── fonts/                  # Font files
+            ├── img/                    # Images used by the default theme
+            ├── js/                     # JavaScript files in ES6 syntax
+            ├── scss/                   # SASS files
+        └── vintage/               # Assets for the vintage template, before compilation
+            └── ...
+    COPYING          # Shaarli license
+    inc/             # static assets and 3rd party libraries
+        └── rain.tpl.class.php     # RainTPL templating library
+    images/          # Images and icons used in Shaarli
+    data/            # data storage: bookmark database, configuration, logs, banlist...
+        ├── config.json.php        # Shaarli configuration (login, password, timezone, title...)
+        ├── datastore.php          # Your link database (compressed).
+        ├── ipban.php              # IP address ban system data
+        ├── lastupdatecheck.txt    # Update check timestamp file
+        └── log.txt                # login/IPban log.
+    tpl/             # RainTPL templates for Shaarli. They are used to build the pages.
+        ├── default/               # Default Shaarli theme
+            ├── fonts/                  # Font files
+            ├── img/                    # Images
+            ├── js/                     # JavaScript files compiled by Babel and compatible with all browsers
+            ├── css/                    # CSS files compiled with SASS
+        └── vintage/               # Legacy Shaarli theme
+            └── ...
+    cache/           # thumbnails cache
+                     # This directory is automatically created. You can erase it anytime you want.
+    tmp/             # Temporary directory for compiled RainTPL templates.
+                     # This directory is automatically created. You can erase it anytime you want.
+    vendor/          # Third-party dependencies. This directory is created by Composer
+```
+
+Shaarli needs read access to:
+
+- the root index.php file
+- the `application/`, `plugins/` and `inc/` directories (recursively)
+
+Shaarli needs read/write access to the `cache/`, `data/`, `pagecache/`, and `tmp/` directories
+
+
+## Automation
+
+A [`Makefile`](https://github.com/shaarli/Shaarli/blob/master/Makefile) is available to perform project-related operations:
+
+- [Static analysis](#Static-analysis) - check that the code is compliant to PHP conventions
+- [Unit tests](#Unit-tests) - ensure there are no regressions introduced by new commits
+- Documentation - generate a local HTML copy of the markdown documentation
+
+### Continuous Integration
+
+[Travis CI](http://docs.travis-ci.com/) is a Continuous Integration build server, that runs a build:
+
+- each time a commit is merged to the mainline (`master` branch)
+- each time a Pull Request is submitted or updated
+
+After all jobs have finished, Travis returns the results to GitHub:
+
+- a status icon represents the result for the `master` branch: [![](https://api.travis-ci.org/shaarli/Shaarli.svg)](https://travis-ci.org/shaarli/Shaarli)
+- Pull Requests are updated with the Travis build result.
+
+See [`.travis.yml`](https://github.com/shaarli/Shaarli/blob/master/.travis.yml).
+
+
+### Documentation
+
+[mkdocs](https://www.mkdocs.org/) is used to convert markdown documentation to HTML pages. The [public documentation](https://shaarli.readthedocs.io/en/master/) website is rendered and hosted by [readthedocs.org](https://readthedocs.org/). A copy of the documentation is also included in prebuilt [release archives](https://github.com/shaarli/Shaarli/releases) (`doc/html/` path in your Shaarli installation). To generate the HTML documentation locally, install a recent version of Python `setuptools` and run    `make doc`.
+
+
+## Static analysis
+
+Patches should try to stick to the [PHP Standard Recommendations](http://www.php-fig.org/psr/) (PSR), especially:
+
+- [PSR-1](http://www.php-fig.org/psr/psr-1/) - Basic Coding Standard
+- [PSR-2](http://www.php-fig.org/psr/psr-2/) - Coding Style Guide
+
+
+**Work in progress:** Static analysis is currently being discussed here: in [#95 - Fix coding style (static analysis)](https://github.com/shaarli/Shaarli/issues/95), [#130 - Continuous Integration tools & features](https://github.com/shaarli/Shaarli/issues/130)
+
+Static analysis tools can be installed with Composer, and used through Shaarli's [Makefile](https://github.com/shaarli/Shaarli/blob/master/Makefile).
+
+For an overview of the available features, see:
+
+- [Code quality: Makefile to run static code checkers](https://github.com/shaarli/Shaarli/pull/124) (#124)
+- [Run PHPCS against different coding standards](https://github.com/shaarli/Shaarli/pull/276) (#276)
similarity index 66%
rename from doc/md/GnuPG-signature.md
rename to doc/md/dev/GnuPG-signature.md
index d1fc10a59602fd8046504c11c7f3af7b8c84dbbb..255780013a99a13a67a3d62fe482ca49068c3948 100644 (file)
@@ -1,24 +1,16 @@
 ## Introduction
 ### PGP and GPG
-[Gnu Privacy Guard](https://gnupg.org/) (GnuPG) is an Open Source implementation of the
-[Pretty Good Privacy](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP)
-(OpenPGP) specification. Its main purposes are digital authentication, signature and encryption.
+[Gnu Privacy Guard](https://gnupg.org/) (GnuPG) is an Open Source implementation of the [Pretty Good Privacy](https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP) (OpenPGP) specification. Its main purposes are digital authentication, signature and encryption. It is often used by the [FLOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) community to verify:
 
-It is often used by the [FLOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) community to verify:
+- Linux package signatures: Debian [SecureApt](https://wiki.debian.org/SecureApt), ArchLinux [Master Keys](https://www.archlinux.org/master-keys/)
+- [Version control](https://en.wikipedia.org/wiki/Revision_control) releases & maintainer identity
 
-- Linux package signatures: Debian [SecureApt](https://wiki.debian.org/SecureApt), ArchLinux [Master 
-Keys](https://www.archlinux.org/master-keys/)
-- [SCM](https://en.wikipedia.org/wiki/Revision_control) releases & maintainer identity
+> You MUST understand that presence of data in the keyserver (pools) in no way connotes trust. Anyone can generate a key, with any name or email address, and upload it. All security and trust comes from evaluating security at the “object level”, via PGP [Web of trust](https://en.wikipedia.org/wiki/Web_of_trust) signatures. This keyserver makes it possible to retrieve keys, looking them up via various indices, but the collection of keys in this public pool is KNOWN to contain malicious and fraudulent keys. It is the common expectation of server operators that users understand this and use software which, like all known common OpenPGP implementations, evaluates trust accordingly. This expectation is so common that it is not normally explicitly stated.
 
-### Trust
-To quote Phil Pennock (the author of the [SKS](https://bitbucket.org/skskeyserver/sks-keyserver/wiki/Home) key server - http://sks.spodhuis.org/):
+-- Phil Pennock (author of the [SKS](https://bitbucket.org/skskeyserver/sks-keyserver/wiki/Home) key server - http://sks.spodhuis.org/)
 
-> You MUST understand that presence of data in the keyserver (pools) in no way connotes trust. Anyone can generate a key, with any name or email address, and upload it. All security and trust comes from evaluating security at the “object level”, via PGP Web-Of-Trust signatures. This keyserver makes it possible to retrieve keys, looking them up via various indices, but the collection of keys in this public pool is KNOWN to contain malicious and fraudulent keys. It is the common expectation of server operators that users understand this and use software which, like all known common OpenPGP implementations, evaluates trust accordingly. This expectation is so common that it is not normally explicitly stated.
+Trust can be gained by having your key signed by other people (and signing their key back, too :) ), for instance during [key signing parties](https://en.wikipedia.org/wiki/Key_signing_party): [Keysigning party HOWTO](http://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html),
 
-Trust can be gained by having your key signed by other people (and signing their key back, too :) ), for instance during [key signing parties](https://en.wikipedia.org/wiki/Key_signing_party), see:
-
-- [The Keysigning party HOWTO](http://www.cryptnet.net/fdp/crypto/keysigning_party/en/keysigning_party.html)
-- [Web of trust](https://en.wikipedia.org/wiki/Web_of_trust)
 
 ## Generate a GPG key
 - [Generating a GPG key for Git tagging](http://stackoverflow.com/a/16725717) (StackOverflow)
similarity index 83%
rename from doc/md/Plugin-System.md
rename to doc/md/dev/Plugin-system.md
index f264e8735d79042506678327f1ae4e503b2a5738..c29774de05b46e47be8ed6c5b05b5aa539e68028 100644 (file)
@@ -1,19 +1,16 @@
-[**I am a developer: ** Developer API](#developer-api)
-
-[**I am a template designer: ** Guide for template designers](#guide-for-template-designer)
-
----
+# Plugin system
 
 ## Developer API
 
 ### What can I do with plugins?
 
-The plugin system let you:
+The plugin system lets you:
 
 - insert content into specific places across templates.
 - alter data before templates rendering.
 - alter data before saving new links.
 
+
 ### How can I create a plugin for Shaarli?
 
 First, chose a plugin name, such as `demo_plugin`.
@@ -30,6 +27,7 @@ You should have the following tree view:
 |   |---| demo_plugin.php
 ```
 
+
 ### Plugin initialization
 
 At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function in the <plugin_name>.php to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter.
@@ -63,6 +61,7 @@ For example, if my plugin want to add data to the header, this function is neede
 
 If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header.
 
+
 ### Plugin's data
 
 #### Parameters
@@ -73,6 +72,26 @@ Every hook function has a `$data` parameter. Its content differs for each hooks.
 
     return $data;
 
+#### Special data
+
+Special additional data are passed to every hook through the
+`$data` parameter to give you access to additional context, and services.
+
+Complete list:
+
+  * `_PAGE_` (string): if the current hook is used to render a template, its name is passed through this additional parameter.
+  * `_LOGGEDIN_` (bool): whether the user is logged in or not.
+  * `_BASE_PATH_` (string): if Shaarli instance is hosted under a subfolder, contains the subfolder path to `index.php` (e.g. `https://domain.tld/shaarli/` -> `/shaarli/`).
+  * `_BOOKMARK_SERVICE_` (`BookmarkServiceInterface`): bookmark service instance, for advanced usage.
+
+Example:
+
+```php
+if ($data['_PAGE_'] === TemplatePage::LINKLIST && $data['LOGGEDIN'] === true) {
+    // Do something for logged in users when the link list is rendered
+}
+```
+
 #### Filling templates placeholder
 
 Template placeholders are displayed in template in specific places.
@@ -89,13 +108,14 @@ array_push($data['top_placeholder'], 'My', 'content');
 return $data;
 ```
 
+
 #### Data manipulation
 
 When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
 
 The data contained by this array can be altered before template rendering.
 
-For exemple, in linklist, it is possible to alter every title:
+For example, in linklist, it is possible to alter every title:
 
 ```php
 // mind the reference if you want $data to be altered
@@ -119,12 +139,28 @@ Each file contain two keys:
 
 > Note: In PHP, `parse_ini_file()` seems to want strings to be between by quotes `"` in the ini file.
 
+### Understanding relative paths
+
+Because Shaarli is a self-hosted tool, an instance can either be installed at the root directory, or under a subfolder.
+This means that you can *never* use absolute paths (eg `/plugins/mything/file.png`).
+
+If a file needs to be included in server end, use simple relative path:
+`PluginManager::$PLUGINS_PATH . '/mything/template.html'`.
+
+If it needs to be included in front end side (e.g. an image),
+the relative path must be prefixed with special data `_BASE_PATH_`:
+`($data['_BASE_PATH_'] ?? '') . '/' . PluginManager::$PLUGINS_PATH . '/mything/picture.png`.
+
+Note that special placeholders for CSS and JS files (respectively `css_files` and `js_files`) are already prefixed
+with the base path in template files.
+
 ### It's not working!
 
 Use `demo_plugin` as a functional example. It covers most of the plugin system features.
 
 If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).
 
+
 ### Hooks
 
 | Hooks         | Description   |
@@ -145,19 +181,16 @@ If it's still not working, please [open an issue](https://github.com/shaarli/Sha
 | [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
 
 
-
 #### render_header
 
-Triggered on every page.
+Triggered on every page - allows plugins to add content in page headers.
 
-Allow plugin to add content in page headers.
 
 ##### Data
 
 `$data` is an array containing:
 
-- `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -175,18 +208,16 @@ List of placeholders:
 
 ![fields_toolbar_example](http://i.imgur.com/3GMifI2.png)
 
-#### render_includes
 
-Triggered on every page.
+#### render_includes
 
-Allow plugin to include their own CSS files.
+Triggered on every page - allows plugins to include their own CSS files.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -198,18 +229,18 @@ List of placeholders:
 
 > Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
 
+
 #### render_footer
 
 Triggered on every page.
 
 Allow plugin to add content in page footer and include their own JS files.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -226,20 +257,21 @@ List of placeholders:
 
 > Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`.
 
+
 #### render_linklist
 
 Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
 
 It allows to add content at the begining and end of the page, after every link displayed and to alter link data.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
-- All templates data, including links.
+  - All templates data, including links.
+  - [Special data](#special-data)
 
-##### Template placeholders
+##### template placeholders
 
 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
 
@@ -261,19 +293,21 @@ List of placeholders:
 
 ![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)
 
+
 #### render_editlink
 
 Triggered when the link edition form is displayed.
 
 Allow to add fields in the form, or display elements.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- All templates data.
+  - All templates data.
+  - [Special data](#special-data)
 
-##### Template placeholders
+##### template placeholders
 
 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
 
@@ -283,19 +317,21 @@ List of placeholders:
 
 ![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)
 
+
 #### render_tools
 
 Triggered when the "tools" page is displayed.
 
 Allow to add content at the end of the page.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- All templates data.
+  - All templates data.
+  - [Special data](#special-data)
 
-##### Template placeholders
+##### template placeholders
 
 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
 
@@ -305,20 +341,21 @@ List of placeholders:
 
 ![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)
 
+
 #### render_picwall
 
 Triggered when picwall is displayed.
 
 Allow to add content at the top and bottom of the page.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
-- All templates data.
+  - All templates data.
+  - [Special data](#special-data)
 
-##### Template placeholders
+##### template placeholders
 
 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
 
@@ -329,18 +366,19 @@ List of placeholders:
 
 ![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)
 
+
 #### render_tagcloud
 
 Triggered when tagcloud is displayed.
 
 Allow to add content at the top and bottom of the page.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
-- All templates data.
+  - All templates data.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -360,16 +398,14 @@ For each tag, the following placeholder can be used:
 
 #### render_taglist
 
-Triggered when taglist is displayed.
-
-Allow to add content at the top and bottom of the page.
+Triggered when taglist is displayed - allows to add content at the top and bottom of the page.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
-- All templates data.
+  - All templates data.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -390,12 +426,13 @@ Triggered when tagcloud is displayed.
 
 Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.
 
-##### Data
+
+##### data
 
 `$data` is an array containing:
 
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
-- All templates data, including links.
+  - All templates data, including links.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -410,19 +447,19 @@ List of placeholders:
 - `plugin_start_zone`: before displaying the template content.
 - `plugin_end_zone`: after displaying the template content.
 
+
 #### render_feed
 
 Triggered when the ATOM or RSS feed is displayed.
 
 Allow to add tags in the feed, either in the header or for each items. Items (links) can also be altered before being rendered.
 
-##### Data
+##### data
 
 `$data` is an array containing:
 
-- `_LOGGEDIN_`: true if user is logged in, false otherwise.
-- `_PAGE_`: containing either `rss` or `atom`.
-- All templates data, including links.
+  - All templates data, including links.
+  - [Special data](#special-data)
 
 ##### Template placeholders
 
@@ -436,13 +473,14 @@ For each links:
 
 - `feed_plugins`: additional tag for every link entry.
 
+
 #### save_link
 
 Triggered when a link is save (new link or edit).
 
 Allow to alter the link being saved in the datastore.
 
-##### Data
+##### data
 
 `$data` is an array containing the link being saved:
 
@@ -456,6 +494,8 @@ Allow to alter the link being saved in the datastore.
 - created
 - updated
 
+Also [special data](#special-data).
+
 
 #### delete_link
 
@@ -463,9 +503,9 @@ Triggered when a link is deleted.
 
 Allow to execute any action before the link is actually removed from the datastore
 
-##### Data
+##### data
 
-`$data` is an array containing the link being saved:
+`$data` is an array containing the link being deleted:
 
 - id
 - title
@@ -477,6 +517,7 @@ Allow to execute any action before the link is actually removed from the datasto
 - created
 - updated
 
+Also [special data](#special-data).
 
 #### save_plugin_parameters
 
@@ -485,15 +526,16 @@ Triggered when the plugin parameters are saved from the plugin administration pa
 Plugins can perform an action every times their settings are updated.
 For example it is used to update the CSS file of the `default_colors` plugins.
 
-##### Data
+##### data
 
 `$data` input contains the `$_POST` array.
 
 So if the plugin has a parameter called `MYPLUGIN_PARAMETER`,
 the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
 
+Also [special data](#special-data).
 
-## Guide for template designer
+## Guide for template designers
 
 ### Plugin administration
 
diff --git a/doc/md/dev/Release-Shaarli.md b/doc/md/dev/Release-Shaarli.md
new file mode 100644 (file)
index 0000000..2c77240
--- /dev/null
@@ -0,0 +1,145 @@
+# Release Shaarli
+
+## Requirements
+
+This guide assumes that you have:
+
+- a GPG key matching your GitHub authentication credentials/email (the email address identified by the GPG key is the same as the one in your `~/.gitconfig`)
+- a GitHub fork of Shaarli
+- a local clone of your Shaarli fork, with the following remotes:
+    - `origin` pointing to your GitHub fork
+    - `upstream` pointing to the main Shaarli repository
+- maintainer permissions on the main Shaarli repository, to:
+    - push the signed tag
+    - create a new release
+- [Composer](https://getcomposer.org/) needs to be installed
+- The [venv](https://docs.python.org/3/library/venv.html) Python 3 module needs to be installed for HTML documentation generation.
+
+## Release notes and `CHANGELOG.md`
+
+GitHub allows drafting the release notes for the upcoming release, from the [Releases](https://github.com/shaarli/Shaarli/releases) page. This way, the release note can be drafted while contributions are merged to `master`. See http://keepachangelog.com/en/0.3.0/ for changelog formatting.
+
+`CHANGELOG.md` should contain the same information as the release note draft for the upcoming version. Update it to:
+
+- add new entries (additions, fixes, etc.)
+- mark the current version as released by setting its date and link
+- add a new section for the future unreleased version
+
+```bash
+## [v0.x.y](https://github.com/shaarli/Shaarli/releases/tag/v0.x.y) - UNRELEASES
+
+### Added
+
+### Changed
+
+### Fixed
+
+### Removed
+
+### Deprecated
+
+### Security
+
+```
+
+
+## Update the list of Git contributors
+
+```bash
+$ make authors
+$ git commit -s -m "Update AUTHORS"
+```
+
+## Create and merge a Pull Request
+
+Create a Pull Request to marge changes from your remote, into `master` in the community Shaarli repository, and have it merged.
+
+
+## Create the release branch and update shaarli_version.php
+
+```bash
+# fetch latest changes from master to your local copy
+git checkout master
+git pull upstream master
+
+# If releasing a new minor version, create a release branch
+$ git checkout -b v0.x
+
+# Bump shaarli_version.php from dev to 0.x.0, **without the v**
+$ vim shaarli_version.php
+$ git add shaarli_version
+$ git commit -s -m "Bump Shaarli version to v0.x.0"
+$ git push upstream v0.x
+```
+
+## Create and push a signed tag
+
+Git [tags](http://git-scm.com/book/en/v2/Distributed-Git-Maintaining-a-Project#Tagging-Your-Releases) are used to identify specific revisions with a unique version number that follows [semantic versioning](https://semver.org/)
+
+```bash
+# update your local copy
+git checkout v0.5
+git pull upstream v0.5
+
+# create a signed tag
+git tag -s -m "Release v0.5.0" v0.5.0
+
+# push the tag to upstream
+git push --tags upstream
+```
+
+Here is how to verify a signed tag. [`v0.5.0`](https://github.com/shaarli/Shaarli/releases/tag/v0.5.0) is the first GPG-signed tag pushed on the Community Shaarli. Let's have a look at its signature!
+
+```bash
+# update the list of available tags
+git fetch upstream
+
+# get the SHA1 reference of the tag
+git show-ref tags/v0.5.0
+# gives: f7762cf803f03f5caf4b8078359a63783d0090c1 refs/tags/v0.5.0
+
+# verify the tag signature information
+git verify-tag f7762cf803f03f5caf4b8078359a63783d0090c1
+# gpg: Signature made Thu 30 Jul 2015 11:46:34 CEST using RSA key ID 4100DF6F
+# gpg: Good signature from "VirtualTam <virtualtam@flibidi.net>" [ultimate]
+```
+
+## Publish the GitHub release
+
+- In the `master` banch, update version badges in `README.md` to point to the newly released Shaarli version
+- Update the previously drafted [release](https://github.com/shaarli/Shaarli/releases) (notes, tag) and publish it
+- Profit!
+
+
+## Generate full release zip archives
+
+Release archives will contain Shaarli code plus all required third-party libraries. They are useful for users who:
+
+- have no SSH access, no possibility to install PHP packages/server extensions, no possibility to run scripts (shared hosting)
+- do not want to install build/dev dependencies on their server
+
+ `git checkout` the appropriate branch, then:
+
+```bash
+# checkout the appropriate branch
+git checkout 0.x.y
+# generate zip archives
+make release_archive
+```
+
+This will create `shaarli-v0.x.y-full.tar`, `shaarli-v0.x.y-full.zip`. These archives need to be manually uploaded on the previously created GitHub [release](https://github.com/shaarli/Shaarli/releases).
+
+
+### Update the `latest` branch
+
+```bash
+# checkout the 'latest' branch
+git checkout latest
+# merge changes from your newly published release branch
+git merge v0.x.y
+# fix eventual conflicts with git mergetool...
+# run tests
+make test
+# push the latest branch
+git push upstream latest
+```
similarity index 95%
rename from doc/md/Theming.md
rename to doc/md/dev/Theming.md
index eb84e11c7ecf40056373fdd2bec539690c654a59..1ad30465b163106938e93b11b2037b120b4f4f15 100644 (file)
@@ -1,3 +1,5 @@
+# Theming
+
 ## Foreword
 
 There are two ways of customizing how Shaarli looks:
@@ -43,6 +45,7 @@ Installation:
 - [kalvn/shaarli-blocks](https://github.com/kalvn/shaarli-blocks) - A template/theme for Shaarli
 - [kalvn/Shaarli-Material](https://github.com/kalvn/Shaarli-Material) - A theme (template) based on Google's Material Design for Shaarli, the superfast delicious clone
 - [ManufacturaInd/shaarli-2004licious-theme](https://github.com/ManufacturaInd/shaarli-2004licious-theme) - A template/theme as a humble homage to the early looks of the del.icio.us site
+- [xfnw/shaarli-default-dark](https://github.com/xfnw/shaarli-default-dark) - The default theme but nice and dark for your eyeballs
 
 ### Shaarli forks
 
similarity index 66%
rename from doc/md/Translations.md
rename to doc/md/dev/Translations.md
index c23ec9627ba3c9e17eb9dfcf3bce12043443ad55..8f3b8f10c45f23151eb7d21b6ebe12a66aca6ff1 100644 (file)
@@ -7,87 +7,80 @@ Note that only the `default` theme supports translations.
 
 ### Contributing
 
-We encourage the community to contribute to Shaarli's translation either by improving existing
-translations or submitting a new language.
+We encourage the community to contribute to Shaarli translations, either by improving existing translations or submitting a new language.
 
-Contributing to the translation does not require development skill.
+Contributing to the translation does not require software development knowledge.
 
-Please submit a pull request with the `.po` file updated/created. Note that the compiled file (`.mo`)
-is not stored on the repository, and is generated during the release process.
+Please submit a pull request with the `.po` file updated/created. Note that the compiled file (`.mo`) is not stored on the repository, and is generated during the release process.
 
-### How to
-
-First, install [Poedit](https://poedit.net/) tool.
-
-Poedit will extract strings to translate from the PHP source code.
 
-**Important**: due to the usage of a template engine, it's important to generate PHP cache files to extract
-every translatable string.
+### How to
 
-You can either use [this script](https://gist.github.com/ArthurHoaro/5d0323f758ab2401ef444a53f54e9a07)  (recommended)
-or visit every template page in your browser to generate cache files, while logged in.
+Install [Poedit](https://poedit.net/) (used to extract strings to translate from the PHP source code, and generate `.po` files).
 
-Here is a list :
+Due to the usage of a template engine, it's important to generate PHP cache files to extract every translatable string. You can either use [this script](https://gist.github.com/ArthurHoaro/5d0323f758ab2401ef444a53f54e9a07) (recommended) or visit every template page in your browser to generate cache files, while logged in. Here is a list :
 
 ```
 http://<replace_domain>/
+http://<replace_domain>/login
+http://<replace_domain>/daily
+http://<replace_domain>/tags/cloud
+http://<replace_domain>/tags/list
+http://<replace_domain>/picture-wall
 http://<replace_domain>/?nonope
 http://<replace_domain>/admin/add-shaare
 http://<replace_domain>/admin/password
 http://<replace_domain>/admin/tags
 http://<replace_domain>/admin/configure
 http://<replace_domain>/admin/tools
-http://<replace_domain>/daily
 http://<replace_domain>/admin/shaare
 http://<replace_domain>/admin/export
 http://<replace_domain>/admin/import
-http://<replace_domain>/login
-http://<replace_domain>/picture-wall
 http://<replace_domain>/admin/plugins
-http://<replace_domain>/tags/cloud
-http://<replace_domain>/tags/list
 ```
 
-#### Improve existing translation
-
-In Poedit, click on "Edit a Translation", and from Shaarli's directory open
-`inc/languages/<lang>/LC_MESSAGES/shaarli.po`.
 
-The existing list of translatable strings should have been loaded, then click on the "Update" button.
+#### Improve existing translations
 
-You can start editing the translation.
+- In Poedit, click on "Edit a Translation
+- Open `inc/languages/<lang>/LC_MESSAGES/shaarli.po` under Shaarli's directory
+- The existing list of translatable strings should load
+- Click on the "Update" button.
+- Start editing translations.
 
 ![poedit-screenshot](images/poedit-1.jpg)
 
 Save when you're done, then you can submit a pull request containing the updated `shaarli.po`.
 
-#### Add a new language
-
-Open Poedit and select "Create New Translation", then from Shaarli's directory open
-`inc/languages/<lang>/LC_MESSAGES/shaarli.po`.
-
-Then select the language you want to create.
 
-Click on `File > Save as...`, and save your file in `<shaarli directory>/inc/language/<new language>/LC_MESSAGES/shaarli.po`.
-`<new language>` here should be the language code respecting the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2)
-format in lowercase (e.g. `de` for German).
+#### Add a new language
 
-Then click on the "Update" button, and you can start to translate every available string.
+- In Poedit select "Create New Translation"
+- Open `inc/languages/<lang>/LC_MESSAGES/shaarli.po` under Shaarli's directory
+- Select the language you want to create.
+- Click on `File > Save as...`, save your file in `<shaarli directory>/inc/language/<new language>/LC_MESSAGES/shaarli.po` (`<new language>` here should be the language code respecting the [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-2) format in lowercase - e.g. `de` for German)
+- Click on the "Update" button
+- Start editing translations.
 
 Save when you're done, then you can submit a pull request containing the new `shaarli.po`.
 
+
 ### Theme translations
 
-Theme translation extensions are loaded automatically if they're present.
+[Theme](Theming) translation extensions are loaded automatically if they're present.
 
 As a theme developer, all you have to do is to add the `.po` and `.mo` compiled file like this:
 
-    tpl/<theme name>/language/<lang>/LC_MESSAGES/<theme name>.po
-    tpl/<theme name>/language/<lang>/LC_MESSAGES/<theme name>.mo
+```
+tpl/<theme name>/language/<lang>/LC_MESSAGES/<theme name>.po
+tpl/<theme name>/language/<lang>/LC_MESSAGES/<theme name>.mo
+```
 
 Where `<lang>` is the ISO 3166-1 alpha-2 language code.
+
 Read the following section "Extend Shaarli's translation" to learn how to generate those files.
 
+
 ### Extend Shaarli's translation
 
 If you're writing a custom theme, or a non official plugin, you might want to use the translation system,
diff --git a/doc/md/dev/Unit-tests.md b/doc/md/dev/Unit-tests.md
new file mode 100644 (file)
index 0000000..fd286bf
--- /dev/null
@@ -0,0 +1,133 @@
+# Unit tests
+
+Shaarli uses the [PHPUnit](https://phpunit.de/) test framework; it can be installed with [Composer](https://getcomposer.org/), which is a dependency management tool.
+
+## Install composer
+
+You can either use:
+
+- a system-wide version, e.g. installed through your distro's package manager
+- a local version, downloadable [here](https://getcomposer.org/download/).
+
+```bash
+# for Debian-based distros
+sudo apt install composer
+```
+
+
+## Install Shaarli dev dependencies
+
+```bash
+$ cd /path/to/shaarli
+$ make composer_dependencies_dev
+```
+
+## Install and enable Xdebug to generate PHPUnit coverage reports
+
+
+[Xdebug](http://xdebug.org/docs/install) is a PHP extension which provides debugging and profiling capabilities. Install Xdebug:
+
+```bash
+# for Debian-based distros:
+sudo apt install php-xdebug
+
+# for ArchLinux:
+pacman -S xdebug
+
+# then add the following line to /etc/php/php.ini
+zend_extension=xdebug.so
+```
+
+## Run unit tests
+
+Ensure tests pass successuflly:
+
+```bash
+make test
+# ...
+# OK (36 tests, 65 assertions)
+```
+
+In case of failure the test suite will point you to actual errors and output a summary:
+
+```bash
+make test
+# ...
+# FAILURES!
+# Tests: 36, Assertions: 63, Errors: 1, Failures: 2.
+```
+
+By default, PHPUnit will run all suitable tests found under the `tests` directory. Each test has 3 possible outcomes:
+
+- `.` - success
+- `F` - failure: the test was run but its results are invalid
+    - the code does not behave as expected
+    - dependencies to external elements: globals, session, cache...
+- `E` - error: something went wrong and the tested code has crashed
+    - typos in the code, or in the test code
+    - dependencies to missing external elements
+
+If Xdebug has been installed and activated, two coverage reports will be generated:
+
+- a summary in the console
+- a detailed HTML report with metrics for tested code
+    - to open it in a web browser: `firefox coverage/index.html &`
+
+
+### Executing specific tests
+
+Add a [`@group`](https://phpunit.de/manual/current/en/appendixes.annotations.html#appendixes.annotations.group) annotation in a test class or method comment:
+
+```php
+/**
+ * Netscape bookmark import
+ * @group WIP
+ */
+class BookmarkImportTest extends PHPUnit_Framework_TestCase
+{
+   [...]
+}
+```
+
+To run all tests annotated with `@group WIP`:
+```bash
+$ vendor/bin/phpunit --group WIP tests/
+```
+
+## Running tests inside Docker containers
+
+Unit tests can be run inside [Docker](../Docker.md) containers.
+
+Test Dockerfiles are located under `tests/docker/<distribution>/Dockerfile`, and can be used to build Docker images to run Shaarli test suites under commonLinux environments. Dockerfiles are provided for the following environments:
+
+- [`alpine36`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/alpine36/Dockerfile) - [Alpine Linux 3.6](https://www.alpinelinux.org/downloads/)
+- [`debian8`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/debian8/Dockerfile) - [Debian 8 Jessie](https://www.debian.org/DebianJessie) (oldoldstable)
+- [`debian9`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/debian9/Dockerfile) - [Debian 9 Stretch](https://wiki.debian.org/DebianStretch) (oldstable)
+- [`ubuntu16`](https://github.com/shaarli/Shaarli/blob/master/tests/docker/ubuntu16/Dockerfile) - [Ubuntu 16.04 Xenial Xerus](http://releases.ubuntu.com/16.04/) (old LTS)
+
+Each image provides:
+- a base Linux OS
+- Shaarli PHP dependencies (OS packages)
+- test PHP dependencies (OS packages)
+- Composer
+- Tests that run inside the conatiner using a standard Linux user account (running tests as `root` would bypass permission checks and may hide issues)
+
+Build a test image:
+
+```bash
+# build the Debian 9 Docker image
+cd /path/to/shaarli/tests/docker/debian9
+docker build -t shaarli-test:debian9 .
+```
+
+Run unit tests in a container:
+
+```bash
+cd /path/to/shaarli
+# install/update 3rd-party test dependencies
+composer install --prefer-dist
+# run tests using the freshly built image
+docker run -v $PWD:/shaarli shaarli-test:debian9 docker_test
+# run the full test campaign
+docker run -v $PWD:/shaarli shaarli-test:debian9 docker_all_tests
+```
similarity index 58%
rename from doc/md/Versioning-and-Branches.md
rename to doc/md/dev/Versioning.md
index 7097ca0a9023c747c93bdd182cb4fdbb32f744f5..32c80a5cee89cb315200b53076bf615b08add415 100644 (file)
@@ -1,6 +1,7 @@
-**WORK IN PROGRESS**
+# Versioning
+
+If you're maintaining a 3rd party tool for Shaarli (theme, plugin, etc.), It's important to understand how Shaarli branches work ensure your tool stays compatible.
 
-It's important to understand how Shaarli branches work, especially if you're maintaining a 3rd party tools for Shaarli (theme, plugin, etc.), to be sure stay compatible.
 
 ## `master` branch
 
@@ -11,39 +12,26 @@ Remarks:
 - This branch shouldn't be used for production as it isn't necessary stable.
 - 3rd party aren't required to be compatible with the latest changes.
 - Official plugins, themes and libraries (contained within Shaarli organization repos) must be compatible with the master branch.
-- The version in this branch is always `dev`.
 
-## `v0.x` branch
 
-This `v0.x` branch, points to the latest `v0.x.y` release.
+## `v0.x` branch
 
-Explanation:
+The `v0.x` branch points to the latest `v0.x.y` release.
 
-When a new version is released, it might contains a major bug which isn't detected right away. For example, a new PHP version is released, containing backward compatibility issue which doesn't work with Shaarli.
+If a major bug affects the original `v0.x.0` release, we may [backport](https://en.wikipedia.org/wiki/Backporting) a fix for this bug from master, to the `v0.x` branch, and create a new bugfix release (eg. `v0.x.1`) from this branch.
 
-In this case, the issue is fixed in the `master` branch, and the fix is backported the to the `v0.x` branch. Then a new release is made from the `v0.x` branch.
+This allows users of the original release to upgrade to the fixed version, without having to upgrade to a completely new minor/major release.
 
-This workflow allow us to fix any major bug detected, without having to release bleeding edge feature too soon.
 
 ## `latest` branch
 
 This branch point the latest release. It recommended to use it to get the latest tested changes.
 
-## `stable` branch
-
-The `stable` branch doesn't contain any major bug, and is one major digit version behind the latest release.
-
-For example, the current latest release is `v0.8.3`, the stable branch is an alias to the latest `v0.7.x` release. When the `v0.9.0` version will be released, the stable will move to the latest `v0.8.x` release.
-
-Remarks:
-
-- Shaarli release pace isn't fast, and the stable branch might be a few months behind the latest release.
 
 ## Releases
 
-Releases are always made from the latest `v0.x` branch.
+For every release, we manually generate a .zip file which contains all Shaarli dependencies, making Shaarli's installation only one step.
 
-Note that for every release, we manually generate a tarball which contains all Shaarli dependencies, making Shaarli's installation only one step.
 
 ## Advices on 3rd party git repos workflow
 
diff --git a/doc/md/docker/docker-101.md b/doc/md/docker/docker-101.md
deleted file mode 100644 (file)
index a9c00b8..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-## Basics
-Install [Docker](https://www.docker.com/), by following the instructions relevant
-to your OS / distribution, and start the service.
-
-### Search an image on [DockerHub](https://hub.docker.com/)
-
-```bash
-$ docker search debian
-
-NAME            DESCRIPTION                                     STARS   OFFICIAL   AUTOMATED
-ubuntu          Ubuntu is a Debian-based Linux operating s...   2065    [OK]
-debian          Debian is a Linux distribution that's comp...   603     [OK]
-google/debian                                                   47                 [OK]
-```
-
-### Show available tags for a repository
-```bash
-$ curl https://index.docker.io/v1/repositories/debian/tags | python -m json.tool
-
-% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
-Dload  Upload   Total   Spent    Left  Speed
-100  1283    0  1283    0     0    433      0 --:--:--  0:00:02 --:--:--   433
-```
-
-Sample output:
-```json
-[
-    {
-        "layer": "85a02782",
-        "name": "stretch"
-    },
-    {
-        "layer": "59abecbc",
-        "name": "testing"
-    },
-    {
-        "layer": "bf0fd686",
-        "name": "unstable"
-    },
-    {
-        "layer": "60c52dbe",
-        "name": "wheezy"
-    },
-    {
-        "layer": "c5b806fe",
-        "name": "wheezy-backports"
-    }
-]
-
-```
-
-### Pull an image from DockerHub
-```bash
-$ docker pull repository[:tag]
-
-$ docker pull debian:wheezy
-wheezy: Pulling from debian
-4c8cbfd2973e: Pull complete
-60c52dbe9d91: Pull complete
-Digest: sha256:c584131da2ac1948aa3e66468a4424b6aea2f33acba7cec0b631bdb56254c4fe
-Status: Downloaded newer image for debian:wheezy
-```
-
-Docker re-uses layers already downloaded. In other words if you have images based on Alpine or some Ubuntu version for example, those can share disk space.
-
-### Start a container
-A container is an instance created from an image, that can be run and that keeps running until its main process exits. Or until the user stops the container. 
-
-The simplest way to start a container from image is ``docker run``. It also pulls the image for you if it is not locally available. For more advanced use, refer to ``docker create``.
-
-Stopped containers are not destroyed, unless you specify ``--rm``. To view all created, running and stopped containers, enter:
-```bash
-$ docker ps -a
-```
-
-Some containers may be designed or configured to be restarted, others are not. Also remember both network ports and volumes of a container are created on start, and not editable later.
-
-### Access a running container
-A running container is accessible using ``docker exec``, or ``docker copy``. You can use ``exec`` to start a root shell in the Shaarli container:
-```bash
-$ docker exec -ti <container-name-or-id> bash
-```
-Note the names and ID's of containers are listed in ``docker ps``. You can even type only one or two letters of the ID, given they are unique.
-
-Access can also be through one or more network ports, or disk volumes. Both are specified on and fixed on ``docker create`` or ``run``.
-
-You can view the console output of the main container process too:
-```bash
-$ docker logs -f <container-name-or-id>
-```
-
-### Docker disk use
-Trying out different images can fill some gigabytes of disk quickly. Besides images, the docker volumes usually take up most disk space.
-
-If you care only about trying out docker and not about what is running or saved, the following commands should help you out quickly if you run low on disk space:
-
-```bash
-$ docker rmi -f $(docker images -aq) # remove or mark all images for disposal
-$ docker volume rm $(docker volume ls -q) # remove all volumes
-```
-
-### Systemd config
-Systemd is the process manager of choice on Debian-based distributions. Once you have a ``docker`` service installed, you can use the following steps to set up Shaarli to run on system start.
-
-```bash
-systemctl enable /etc/systemd/system/docker.shaarli.service
-systemctl start docker.shaarli
-systemctl status docker.*
-journalctl -f # inspect system log if needed
-```
-
-You will need sudo or a root terminal to perform some or all of the steps above. Here are the contents for the service file:
-```
-[Unit]
-Description=Shaarli Bookmark Manager Container
-After=docker.service
-Requires=docker.service
-
-
-[Service]
-Restart=always
-
-# Put any environment you want in an included file, like $host- or $domainname in this example
-EnvironmentFile=/etc/sysconfig/box-environment
-
-# It's just an example..
-ExecStart=/usr/bin/docker run \
-  -p 28010:80 \
-  --name ${hostname}-shaarli \
-  --hostname shaarli.${domainname} \
-  -v /srv/docker-volumes-local/shaarli-data:/var/www/shaarli/data:rw \
-  -v /etc/localtime:/etc/localtime:ro \
-  shaarli/shaarli:latest
-
-ExecStop=/usr/bin/docker rm -f ${hostname}-shaarli
-
-
-[Install]
-WantedBy=multi-user.target
-```
diff --git a/doc/md/docker/resources.md b/doc/md/docker/resources.md
deleted file mode 100644 (file)
index 082d4a4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-### Docker
-
-- [Interactive Docker training portal](https://www.katacoda.com/courses/docker/) on [Katakoda](https://www.katacoda.com/)
-- [Where are Docker images stored?](http://blog.thoward37.me/articles/where-are-docker-images-stored/)
-- [Dockerfile reference](https://docs.docker.com/reference/builder/)
-- [Dockerfile best practices](https://docs.docker.com/articles/dockerfile_best-practices/)
-- [Volumes](https://docs.docker.com/userguide/dockervolumes/)
-
-### DockerHub
-
-- [Repositories](https://docs.docker.com/userguide/dockerrepos/)
-- [Teams and organizations](https://docs.docker.com/docker-hub/orgs/)
-- [GitHub automated build](https://docs.docker.com/docker-hub/github/)
-
-### Service management
-
-- [Using supervisord](https://docs.docker.com/articles/using_supervisord/)
-- [Nginx in the foreground](http://nginx.org/en/docs/ngx_core_module.html#daemon)
-- [supervisord](http://supervisord.org/)
diff --git a/doc/md/docker/reverse-proxy-configuration.md b/doc/md/docker/reverse-proxy-configuration.md
deleted file mode 100644 (file)
index e53c942..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-## Foreword
-
-This guide assumes that:
-
-- Shaarli runs in a Docker container
-- The host's `10080` port is mapped to the container's `80` port
-- Shaarli's Fully Qualified Domain Name (FQDN) is `shaarli.domain.tld`
-- HTTP traffic is redirected to HTTPS
-
-## Apache
-
-- [Apache 2.4 documentation](https://httpd.apache.org/docs/2.4/)
-    - [mod_proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html)
-    - [Reverse Proxy Request Headers](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#x-headers)
-
-The following HTTP headers are set when the `ProxyPass` directive is set:
-
-- `X-Forwarded-For`
-- `X-Forwarded-Host`
-- `X-Forwarded-Server`
-
-The original `SERVER_NAME` can be sent to the proxied host by setting the [`ProxyPreserveHost`](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#ProxyPreserveHost) directive to `On`.
-
-```apache
-<VirtualHost *:80>
-    ServerName shaarli.domain.tld
-    Redirect permanent / https://shaarli.domain.tld
-</VirtualHost>
-
-<VirtualHost *:443>
-    ServerName shaarli.domain.tld
-
-    SSLEngine on
-    SSLCertificateFile    /path/to/cert
-    SSLCertificateKeyFile /path/to/certkey
-
-    LogLevel warn
-    ErrorLog  /var/log/apache2/shaarli-error.log
-    CustomLog /var/log/apache2/shaarli-access.log combined
-
-    RequestHeader set X-Forwarded-Proto "https"
-    ProxyPreserveHost On
-    
-    ProxyPass        / http://127.0.0.1:10080/
-    ProxyPassReverse / http://127.0.0.1:10080/
-</VirtualHost>
-```
-
-
-## HAProxy
-
-- [HAProxy documentation](https://cbonte.github.io/haproxy-dconv/)
-
-```conf
-global
-    [...]
-
-defaults
-    [...]
-
-frontend http-in
-    bind :80
-       redirect scheme https code 301 if !{ ssl_fc }
-
-       bind :443 ssl crt /path/to/cert.pem
-
-       default_backend shaarli
-
-
-backend shaarli
-    mode http
-    option http-server-close
-    option forwardfor
-    reqadd X-Forwarded-Proto: https
-
-    server shaarli1 127.0.0.1:10080
-```
-
-
-## Nginx
-
-- [Nginx documentation](https://nginx.org/en/docs/)
-
-```nginx
-http {
-    [...]
-
-    index index.html index.php;
-
-    root        /home/john/web;
-    access_log  /var/log/nginx/access.log;
-    error_log   /var/log/nginx/error.log;
-
-       server {
-               listen       80;
-               server_name  shaarli.domain.tld;
-               return       301 https://shaarli.domain.tld$request_uri;
-       }
-
-       server {
-               listen       443 ssl http2;
-               server_name  shaarli.domain.tld;
-
-        ssl_certificate       /path/to/cert
-        ssl_certificate_key   /path/to/certkey
-
-               location / {
-                       proxy_set_header  X-Real-IP         $remote_addr;
-                       proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
-                       proxy_set_header  X-Forwarded-Proto $scheme;
-                       proxy_set_header  X-Forwarded-Host  $host;
-
-                       proxy_pass             http://localhost:10080/;
-                       proxy_set_header Host  $host;
-                       proxy_connect_timeout  30s;
-                       proxy_read_timeout     120s;
-
-                       access_log      /var/log/nginx/shaarli.access.log;
-                       error_log       /var/log/nginx/shaarli.error.log;
-               }
-       }
-}
-```
diff --git a/doc/md/docker/shaarli-images.md b/doc/md/docker/shaarli-images.md
deleted file mode 100644 (file)
index 14971d5..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-A brief guide on getting starting using docker is given in [Docker 101](docker-101.md).
-To learn more about user data and how to keep it across versions, please see [Upgrade and Migration](../Upgrade-and-migration.md).
-
-## Get and run a Shaarli image
-
-### DockerHub repository
-The images can be found in the [`shaarli/shaarli`](https://hub.docker.com/r/shaarli/shaarli/)
-repository.
-
-### Available image tags
-- `latest`: latest branch
-- `master`: master branch
-- `stable`: stable branch
-
-The `latest`, `master` and `stable` images rely on:
-
-- [Alpine Linux](https://www.alpinelinux.org/)
-- [PHP7-FPM](http://php-fpm.org/)
-- [Nginx](http://nginx.org/)
-
-Additional Dockerfiles are provided for the `arm32v7` platform, relying on
-[Linuxserver.io Alpine armhf
-images](https://hub.docker.com/r/lsiobase/alpine.armhf/). These images must be
-built using [`docker
-build`](https://docs.docker.com/engine/reference/commandline/build/) on an
-`arm32v7` machine or using an emulator such as
-[qemu](https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/).
-
-### Download from Docker Hub
-```shell
-$ docker pull shaarli/shaarli
-
-latest: Pulling from shaarli/shaarli
-32716d9fcddb: Pull complete
-84899d045435: Pull complete
-4b6ad7444763: Pull complete
-e0345ef7a3e0: Pull complete
-5c1dd344094f: Pull complete
-6422305a200b: Pull complete
-7d63f861dbef: Pull complete
-3eb97210645c: Pull complete
-869319d746ff: Already exists
-869319d746ff: Pulling fs layer
-902b87aaaec9: Already exists
-Digest: sha256:f836b4627b958b3f83f59c332f22f02fcd495ace3056f2be2c4912bd8704cc98
-Status: Downloaded newer image for shaarli/shaarli:latest
-```
-
-### Create and start a new container from the image
-```shell
-# map the host's :8000 port to the container's :80 port
-$ docker create -p 8000:80 shaarli/shaarli
-d40b7af693d678958adedfb88f87d6ea0237186c23de5c4102a55a8fcb499101
-
-# launch the container in the background
-$ docker start d40b7af693d678958adedfb88f87d6ea0237186c23de5c4102a55a8fcb499101
-d40b7af693d678958adedfb88f87d6ea0237186c23de5c4102a55a8fcb499101
-
-# list active containers
-$ docker ps
-CONTAINER ID  IMAGE            COMMAND               CREATED         STATUS        PORTS                 NAMES
-d40b7af693d6  shaarli/shaarli  /usr/bin/supervisor  15 seconds ago  Up 4 seconds  0.0.0.0:8000->80/tcp  backstabbing_galileo
-```
-
-### Stop and destroy a container
-```shell
-$ docker stop backstabbing_galileo  # those docker guys are really rude to physicists!
-backstabbing_galileo
-
-# check the container is stopped
-$ docker ps
-CONTAINER ID  IMAGE            COMMAND               CREATED         STATUS        PORTS                 NAMES
-
-# list ALL containers
-$ docker ps -a
-CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                      PORTS               NAMES
-d40b7af693d6        shaarli/shaarli     /usr/bin/supervisor   5 minutes ago       Exited (0) 48 seconds ago                       backstabbing_galileo
-
-# destroy the container
-$ docker rm backstabbing_galileo  # let's put an end to these barbarian practices
-backstabbing_galileo
-
-$ docker ps -a
-CONTAINER ID  IMAGE            COMMAND               CREATED         STATUS        PORTS                 NAMES
-```
-
-### Automatic builds
-Docker users can start a personal instance from an
-[autobuild image](https://hub.docker.com/r/shaarli/shaarli/).
-For example to start a temporary Shaarli at ``localhost:8000``, and keep session
-data (config, storage):
-
-```shell
-MY_SHAARLI_VOLUME=$(cd /path/to/shaarli/data/ && pwd -P)
-docker run -ti --rm \
-         -p 8000:80 \
-         -v $MY_SHAARLI_VOLUME:/var/www/shaarli/data \
-         shaarli/shaarli
-```
-
-### Volumes and data persistence
-Data can be persisted by [using volumes](https://docs.docker.com/storage/volumes/).
-Volumes allow to keep your data when renewing and/or updating container images:
-
-```shell
-# Create data volumes
-$ docker volume create shaarli-data
-$ docker volume create shaarli-cache
-
-# Create and start a Shaarli container using these volumes to persist data
-$ docker create \
-    --name shaarli \
-    -v shaarli-cache:/var/www/shaarli/cache \
-    -v shaarli-data:/var/www/shaarli/data \
-    -p 8000:80 \
-    shaarli/shaarli:master
-$ docker start shaarli
-```
diff --git a/doc/md/guides/backup-restore-import-export.md b/doc/md/guides/backup-restore-import-export.md
deleted file mode 100644 (file)
index bb79007..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-## Backup and restore the datastore file
-
-Backup the file `data/datastore.php` (by FTP or SSH). Restore by putting the file back in place.
-
-Example command:
-```bash
-rsync -avzP my.server.com:/var/www/shaarli/data/datastore.php datastore-$(date +%Y-%m-%d_%H%M).php
-```
-
-## Export links as...
-
-To export links as an HTML file, under _Tools > Export_, choose:
-
-- _Export all_ to export both public and private links
-- _Export public_ to export public links only
-- _Export private_ to export private links only
-
-Restore by using the `Import` feature.
-
-- This can be done using the [shaarchiver](https://github.com/nodiscc/shaarchiver) tool.
-
-Example command: 
-```bash
-./export-bookmarks.py --url=https://my.server.com/shaarli --username=myusername --password=mysupersecretpassword --download-dir=./ --type=all
-```
-
-## Import links from...
-
-### Diigo
-
-If you export your bookmark from Diigo, make sure you use the Delicious export, not the Netscape export. (Their Netscape export is broken, and they don't seem to be interested in fixing it.)
-
-### Mister Wong
-
-See [this issue](https://github.com/sebsauvage/Shaarli/issues/146) for import tweaks.
-
-### SemanticScuttle
-
-To correctly import the tags from a [SemanticScuttle](http://semanticscuttle.sourceforge.net/) HTML export, edit the HTML file before importing and replace all occurences of `tags=` (lowercase) to `TAGS=` (uppercase).
-
-### Scuttle
-
-Shaarli cannot import data directly from [Scuttle](https://github.com/scronide/scuttle).
-
-However, you can use the third-party [scuttle-to-shaarli](https://github.com/q2apro/scuttle-to-shaarli)
-tool to export the Scuttle database to the Netscape HTML format compatible with the Shaarli importer.
-
-### Refind
-
-You can use the third-party tool [Derefind](https://github.com/ShawnPConroy/Derefind) to convert refind.com bookmark exports to a format that can be imported into Shaarli.
-
-## Import Shaarli links to Firefox
-
-- Export your Shaarli links as described above.
-    - For compatibility reasons, check `Prepend note permalinks with this Shaarli instance's URL (useful to import bookmarks in a web browser)`
-- In Firefox, open the bookmark manager (not the sidebar! `Bookmarks menu > Show all bookmarks` or `Ctrl+Shift+B`)
-- Select `Import and Backup > Import bookmarks in HTML format`
-
-Your bookmarks will be imported in Firefox, ready to use, with tags and descriptions retained. "Self" (notes) shaares will still point to the Shaarli instance you exported them from, but the note text can be viewed directly in the bookmark properties inside your browser. Depending on the number of bookmarks, the import can take some time.
-
-You may be interested in these Firefox addons to manage links imported from Shaarli
-
-- [Bookmark Deduplicator](https://addons.mozilla.org/en-US/firefox/addon/bookmark-deduplicator/) - provides an easy way to deduplicate your bookmarks
-- [TagSieve](https://addons.mozilla.org/en-US/firefox/addon/tagsieve/) - browse your bookmarks by their tags
diff --git a/doc/md/guides/images/01-create-droplet-distro.jpg b/doc/md/guides/images/01-create-droplet-distro.jpg
deleted file mode 100644 (file)
index 63682ba..0000000
Binary files a/doc/md/guides/images/01-create-droplet-distro.jpg and /dev/null differ
diff --git a/doc/md/guides/images/02-create-droplet-region.jpg b/doc/md/guides/images/02-create-droplet-region.jpg
deleted file mode 100644 (file)
index 135a78b..0000000
Binary files a/doc/md/guides/images/02-create-droplet-region.jpg and /dev/null differ
diff --git a/doc/md/guides/images/03-create-droplet-size.jpg b/doc/md/guides/images/03-create-droplet-size.jpg
deleted file mode 100644 (file)
index aa5b2fd..0000000
Binary files a/doc/md/guides/images/03-create-droplet-size.jpg and /dev/null differ
diff --git a/doc/md/guides/images/04-finalize.jpg b/doc/md/guides/images/04-finalize.jpg
deleted file mode 100644 (file)
index 68ec0dc..0000000
Binary files a/doc/md/guides/images/04-finalize.jpg and /dev/null differ
diff --git a/doc/md/guides/images/05-droplet.jpg b/doc/md/guides/images/05-droplet.jpg
deleted file mode 100644 (file)
index 44e93a1..0000000
Binary files a/doc/md/guides/images/05-droplet.jpg and /dev/null differ
diff --git a/doc/md/guides/images/06-domain.jpg b/doc/md/guides/images/06-domain.jpg
deleted file mode 100644 (file)
index 5827dd9..0000000
Binary files a/doc/md/guides/images/06-domain.jpg and /dev/null differ
diff --git a/doc/md/guides/install-shaarli-with-debian9-and-docker.md b/doc/md/guides/install-shaarli-with-debian9-and-docker.md
deleted file mode 100644 (file)
index f1b26d4..0000000
+++ /dev/null
@@ -1,257 +0,0 @@
-_Last updated on 2018-07-01._
-
-## Goals
-- Getting a Virtual Private Server (VPS)
-- Running Shaarli:
-    - as a Docker container,
-    - using the Træfik reverse proxy,
-    - securized with TLS certificates from Let's Encrypt.
-
-
-The following components and tools will be used:
-
-- [Debian](https://www.debian.org/), a GNU/Linux distribution widely used in
-  server environments;
-- [Docker](https://docs.docker.com/engine/docker-overview/), an open platform
-  for developing, shipping, and running applications;
-- [Docker Compose](https://docs.docker.com/compose/), a tool for defining and
-  running multi-container Docker applications.
-
-
-More information can be found in the [Resources](#resources) section at the
-bottom of the guide.
-
-## Getting a Virtual Private Server
-For this guide, I went for the smallest VPS available from DigitalOcean,
-a Droplet with 1 CPU, 1 GiB RAM and 25 GiB SSD storage, which costs
-$5/month ($0.007/hour):
-
-- [Droplets Overview](https://www.digitalocean.com/docs/droplets/overview/)
-- [Pricing](https://www.digitalocean.com/pricing/)
-- [How to Create a Droplet from the DigitalOcean Control Panel](https://www.digitalocean.com/docs/droplets/how-to/create/)
-- [How to Add SSH Keys to Droplets](https://www.digitalocean.com/docs/droplets/how-to/add-ssh-keys/)
-- [Initial Server Setup with Debian 8](https://www.digitalocean.com/community/tutorials/initial-server-setup-with-debian-8) (also applies to Debian 9)
-- [An Introduction to Securing your Linux VPS](https://www.digitalocean.com/community/tutorials/an-introduction-to-securing-your-linux-vps)
-
-### Creating a Droplet
-Select `Debian 9` as the Droplet distribution:
-
-<img src="../images/01-create-droplet-distro.jpg"
-     width="500px"
-     alt="Droplet distribution" />
-
-Choose a region that is geographically close to you:
-
-<img src="../images/02-create-droplet-region.jpg"
-     width="500px"
-     alt="Droplet region" />
-
-Choose a Droplet size that corresponds to your usage and budget:
-
-<img src="../images/03-create-droplet-size.jpg"
-     width="500px"
-     alt="Droplet size" />
-
-Finalize the Droplet creation:
-
-<img src="../images/04-finalize.jpg"
-     width="500px"
-     alt="Droplet finalization" />
-
-Droplet information is displayed on the Control Panel:
-
-<img src="../images/05-droplet.jpg"
-     width="500px"
-     alt="Droplet summary" />
-
-Once your VPS has been created, you will receive an e-mail with connection
-instructions.
-
-## Obtaining a domain name
-After creating your VPS, it will be reachable using its IP address; some hosting
-providers also create a DNS record, e.g. `ns4853142.ip-01-47-127.eu`.
-
-A domain name (DNS record) is required to obtain a certificate and setup HTTPS
-(HTTP with TLS encryption).
-
-Domain names can be obtained from registrars through hosting providers such as
-[Gandi](https://www.gandi.net/en/domain).
-
-Once you have your own domain, you need to create a new DNS record that points
-to your VPS' IP address:
-
-<img src="../images/06-domain.jpg"
-     width="650px"
-     alt="Domain configuration" />
-
-## Host setup
-Now's the time to connect to your freshly created VPS!
-
-```shell
-$ ssh root@188.166.85.8
-
-Linux stretch-shaarli-02 4.9.0-6-amd64 #1 SMP Debian 4.9.88-1+deb9u1 (2018-05-07) x86_64
-
-The programs included with the Debian GNU/Linux system are free software;
-the exact distribution terms for each program are described in the
-individual files in /usr/share/doc/*/copyright.
-
-Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
-permitted by applicable law.
-Last login: Sun Jul  1 11:20:18 2018 from <REDACTED>
-
-root@stretch-shaarli-02:~$
-```
-
-### Updating the system
-```shell
-root@stretch-shaarli-02:~$ apt update && apt upgrade -y
-```
-
-### Setting up Docker
-_The following instructions are from the
-[Get Docker CE for Debian](https://docs.docker.com/install/linux/docker-ce/debian/)
-guide._
-
-Install package dependencies:
-
-```shell
-root@stretch-shaarli-02:~$ apt install -y apt-transport-https ca-certificates curl gnupg2 software-properties-common
-```
-
-Add Docker's package repository GPG key:
-
-```shell
-root@stretch-shaarli-02:~$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
-```
-
-Add Docker's package repository:
-
-```shell
-root@stretch-shaarli-02:~$ add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian stretch stable"
-```
-
-Update package lists and install Docker:
-
-```shell
-root@stretch-shaarli-02:~$ apt update && apt install -y docker-ce
-```
-
-Verify Docker is properly configured by running the `hello-world` image:
-
-```shell
-root@stretch-shaarli-02:~$ docker run hello-world
-```
-
-### Setting up Docker Compose
-_The following instructions are from the
-[Install Docker Compose](https://docs.docker.com/compose/install/)
-guide._
-
-Download the current version from the release page:
-
-```shell
-root@stretch-shaarli-02:~$ curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
-root@stretch-shaarli-02:~$ chmod +x /usr/local/bin/docker-compose
-```
-
-## Running Shaarli
-Shaarli comes with a configuration file for Docker Compose, that will setup:
-
-- a local Docker network
-- a Docker [volume](https://docs.docker.com/storage/volumes/) to store Shaarli data
-- a Docker [volume](https://docs.docker.com/storage/volumes/) to store Træfik TLS configuration and certificates
-- a [Shaarli](https://hub.docker.com/r/shaarli/shaarli/) instance
-- a [Træfik](https://hub.docker.com/_/traefik/) instance
-
-[Træfik](https://docs.traefik.io/) is a modern HTTP reverse proxy, with native
-support for Docker and [Let's Encrypt](https://letsencrypt.org/).
-
-### Compose configuration
-Create a new directory to store the configuration:
-
-```shell
-root@stretch-shaarli-02:~$ mkdir shaarli && cd shaarli
-root@stretch-shaarli-02:~/shaarli$
-```
-
-Download the current version of Shaarli's `docker-compose.yml`:
-
-```shell
-root@stretch-shaarli-02:~/shaarli$ curl -L https://raw.githubusercontent.com/shaarli/Shaarli/master/docker-compose.yml -o docker-compose.yml
-```
-
-Create the `.env` file and fill in your VPS and domain information (replace
-`<MY_SHAARLI_DOMAIN>` and `<MY_CONTACT_EMAIL>` with your actual information):
-
-```shell
-root@stretch-shaarli-02:~/shaarli$ vim .env
-```
-
-```shell
-SHAARLI_VIRTUAL_HOST=<MY_SHAARLI_DOMAIN>
-SHAARLI_LETSENCRYPT_EMAIL=<MY_CONTACT_EMAIL>
-```
-
-### Pull the Docker images
-```shell
-root@stretch-shaarli-02:~/shaarli$ docker-compose pull
-Pulling shaarli ... done
-Pulling traefik ... done
-```
-
-### Run!
-```shell
-root@stretch-shaarli-02:~/shaarli$ docker-compose up -d
-Creating network "shaarli_http-proxy" with the default driver
-Creating volume "shaarli_traefik-acme" with default driver
-Creating volume "shaarli_shaarli-data" with default driver
-Creating shaarli_shaarli_1 ... done
-Creating shaarli_traefik_1 ... done
-```
-
-## Conclusion
-Congratulations! Your Shaarli instance should be up and running, and available
-at `https://<MY_SHAARLI_DOMAIN>`.
-
-<img src="../images/07-installation.jpg"
-     width="500px"
-     alt="Shaarli installation page" />
-
-## Resources
-### Related Shaarli documentation
-- [Docker 101](../docker/docker-101.md)
-- [Shaarli images](../docker/shaarli-images.md)
-
-### Hosting providers
-- [DigitalOcean](https://www.digitalocean.com/)
-- [Gandi](https://www.gandi.net/en)
-- [OVH](https://www.ovh.co.uk/)
-- [RackSpace](https://www.rackspace.com/)
-- etc.
-
-### Domain Names and Registrars
-- [Introduction to the Domain Name System (DNS)](https://opensource.com/article/17/4/introduction-domain-name-system-dns)
-- [ICANN](https://www.icann.org/)
-- [Domain name registrar](https://en.wikipedia.org/wiki/Domain_name_registrar)
-- [OVH Domain Registration](https://www.ovh.co.uk/domains/)
-- [Gandi Domain Registration](https://www.gandi.net/en/domain)
-
-### HTTPS and Security
-- [Transport Layer Security](https://en.wikipedia.org/wiki/Transport_Layer_Security)
-- [Let's Encrypt](https://letsencrypt.org/)
-
-### Docker
-- [Docker Overview](https://docs.docker.com/engine/docker-overview/)
-- [Docker Documentation](https://docs.docker.com/)
-- [Get Docker CE for Debian](https://docs.docker.com/install/linux/docker-ce/debian/)
-- [docker logs](https://docs.docker.com/engine/reference/commandline/logs/)
-- [Volumes](https://docs.docker.com/storage/volumes/)
-- [Install Docker Compose](https://docs.docker.com/compose/install/)
-- [docker-compose logs](https://docs.docker.com/compose/reference/logs/)
-
-### Træfik
-- [Getting Started](https://docs.traefik.io/)
-- [Docker backend](https://docs.traefik.io/configuration/backends/docker/)
-- [Let's Encrypt and Docker](https://docs.traefik.io/user-guide/docker-and-lets-encrypt/)
-- [traefik](https://hub.docker.com/_/traefik/) Docker image
diff --git a/doc/md/guides/various-hacks.md b/doc/md/guides/various-hacks.md
deleted file mode 100644 (file)
index 0cef99d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-### Decode datastore content
-
-To display the array representing the data saved in `data/datastore.php`, use the following snippet:
-
-```php
-$data = "tZNdb9MwFIb... <Commented content inside datastore.php>";
-$out = unserialize(gzinflate(base64_decode($data)));
-echo "<pre>"; // Pretty printing is love, pretty printing is life
-print_r($out);
-echo "</pre>";
-exit;
-```
-This will output the internal representation of the datastore, "unobfuscated" (if this can really be considered obfuscation).
-
-Alternatively, you can transform to JSON format (and pretty-print if you have `jq` installed):
-```
-php -r 'print(json_encode(unserialize(gzinflate(base64_decode(preg_replace("!.*/\* (.+) \*/.*!", "$1", file_get_contents("data/datastore.php")))))));' | jq .
-```
-
-### See also
-
-- [Add a new custom field to shaares (example patch)](https://gist.github.com/nodiscc/8b0194921f059d7b9ad89a581ecd482c)
-- [Copy an existing Shaarli installation over SSH, and serve it locally](https://gist.github.com/nodiscc/ed161c66e5b028b5299b0a3733d01c77)
-- [Create multiple Shaarli instances, generate an HTML index of them](https://gist.github.com/nodiscc/52e711cda3bc47717c16065231cf6b20)
diff --git a/doc/md/images/bookmarklet.png b/doc/md/images/bookmarklet.png
deleted file mode 100644 (file)
index 0262578..0000000
Binary files a/doc/md/images/bookmarklet.png and /dev/null differ
diff --git a/doc/md/images/firefoxshare.png b/doc/md/images/firefoxshare.png
deleted file mode 100644 (file)
index 8f8fdba..0000000
Binary files a/doc/md/images/firefoxshare.png and /dev/null differ
diff --git a/doc/md/images/install-shaarli.png b/doc/md/images/install-shaarli.png
deleted file mode 100644 (file)
index d5d5baa..0000000
Binary files a/doc/md/images/install-shaarli.png and /dev/null differ
index 1431f9e12e68a9a504ff5888a7762ac4f792fd5b..2c4995f8acaa875aa1d13795c5818d441b471291 100644 (file)
@@ -2,21 +2,19 @@
 
 The personal, minimalist, super-fast, database free, bookmarking service.
 
-Do you want to share the links you discover?
-Shaarli is a minimalist bookmark manager and link sharing service that you can install on your own server.
-It is designed to be personal (single-user), fast and handy.
-
-<!-- TODO screenshots -->
+Do you want to share the links you discover? Shaarli is a minimalist bookmark manager and link sharing service that you can install on your own server. It is designed to be personal (single-user), fast and handy.
 
 Visit the pages in the sidebar to find information on how to setup, use, configure, tweak and troubleshoot Shaarli.
 
-
 * [GitHub project page](https://github.com/shaarli/Shaarli)
-* [Online documentation](https://shaarli.readthedocs.io/)
-* [Latest releases](https://github.com/shaarli/Shaarli/releases)
+* [Documentation](https://shaarli.readthedocs.io/)
 * [Changelog](https://github.com/shaarli/Shaarli/blob/master/CHANGELOG.md)
 
 
+[![](https://i.imgur.com/8wEBRSG.png)](https://i.imgur.com/WWPfSj0.png) [![](https://i.imgur.com/93PpLLs.png)](https://i.imgur.com/V09kAQt.png) [![](https://i.imgur.com/rrsjWYy.png)](https://i.imgur.com/TZzGHMs.png) [![](https://i.imgur.com/8iRzHfe.png)](https://i.imgur.com/sfJJ6NT.png) [![](https://i.imgur.com/GjZGvIh.png)](https://i.imgur.com/QsedIuJ.png) [![](https://i.imgur.com/TFZ9PEq.png)](https://i.imgur.com/KdtF8Ll.png) [![](https://i.imgur.com/uICDOle.png)](https://i.imgur.com/27wYsbC.png) [![](https://i.imgur.com/tVvD3gH.png)](https://i.imgur.com/zGF4d6L.jpg)
+
+
+
 ## Demo
 
 You can use this [public demo instance of Shaarli](https://demo.shaarli.org).
@@ -25,101 +23,80 @@ It runs the latest development version of Shaarli and is updated/reset daily.
 Login: `demo`; Password: `demo`
 
 
+## Getting started
+
+- [Configure your server](Server-configuration.md)
+- [Install Shaarli](Installation.md)
+- Or install Shaarli using [Docker](Docker.md)
+
+
 ## Features
 
 Shaarli can be used:
 
-- to share, comment and save interesting links and news
+- to share, comment and save interesting links
 - to bookmark useful/frequent links and share them between computers
 - as a minimal blog/microblog/writing platform
-- as a read-it-later list
-- to draft and save articles/posts/ideas
-- to keep notes, documentation and code snippets
-- as a shared clipboard/notepad/pastebin between machines
-- as a todo list
-- to store media playlists
-- to keep extracts/comments from webpages that may disappear.
-- to keep track of ongoing discussions
-- to feed other blogs, aggregators, social networks... using RSS feeds
+- as a read-it-later/todo list
+- as a notepad to draft and save articles/posts/ideas
+- as a knowledge base to keep notes, documentation and code snippets
+- as a shared clipboard/notepad/pastebin between computers
+- as playlist manager for online media
+- to feed other blogs, aggregators, social networks...
 
 ### Edit, view and search your links
 
-- Minimalist design
-- FAST
-- Customizable link titles and descriptions
-- Tags to organize your links (features tag autocompletion, renaming, merging and deletion)
-- Search by tag or using the full-text search
-- Public and private links (visible only to logged-in users)
-- Unique permalinks for easy reference
-- Paginated link list (with image and video thumbnails)
-- Tag cloud and list views
-- Picture wall: image and video thumbnails view (with lazy loading)
-- ATOM and RSS feeds (can also be filtered using tags or text search)
-- Daily: newspaper-like daily digest (and daily RSS feed)
-- URL cleanup: automatic removal of `?utm_source=...`, `fb=...`
-- Extensible through [plugins](https://shaarli.readthedocs.io/en/master/Plugins/#plugin-usage)
-
-### Easy setup
-
-- Dead-simple installation: drop the files, open the page
-- Links are stored in a file (no database required, easy backup: simply copy the datastore file)
-- Import and export links as Netscape bookmarks compatible with most Web browsers
-
-### Accessibility
-
-- Bookmarklet and other tools to share links in one click
-- Support for mobile browsers
-- Degrades gracefully with Javascript disabled
-- Easy page customization through HTML/CSS/RainTPL
-
-### Security
-
-- Discreet pop-up notification when a new release is available
-- Bruteforce protection on the login form
-- Protected against [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) and session cookie hijacking
+- Editable URL, title, description, tags, private/public status for all your [Shaares](Usage.md)
+- [Tags](Usage.md#tags) to organize your Shaares
+- [Search](Usage.md#search) in all fields
+- Unique [permalinks](Usage.md#permalinks) for easy reference
+- Paginated Shaares list view (with image and video thumbnails)
+- [Tag cloud/list](Usage#tag-cloud) views
+- [Picture wall](Usage#picture-wall)/thumbnails view (with lazy loading)
+- [ATOM and RSS feeds](Usage.md#rss-feeds) (can also be filtered using tags or text search)
+- [Daily](Usage.md#daily): newspaper-like daily digest (and daily RSS feed)
+- URL cleanup: automatic removal of `?utm_source=...`, `fb=...` tracking parameters
+- Extensible through [plugins](Plugins.md)
+- Easily extensible by any client using the [REST API](REST-API.md) exposed by Shaarli
+- Bookmarklet and [other tools](Community-and-related-software.md) to share links in one click
+- Responsive/support for mobile browsers, degrades gracefully with Javascript disabled
 
-<!-- TODO Limitations -->
 
-### REST API
-
-- Easily extensible by any client using the REST API exposed by Shaarli ([API documentation](http://shaarli.github.io/api-documentation/)).
+### Easy setup
 
+- Dead-simple [installation](Installation.md): drop the files on your server, open the page
+- Shaares are stored in a file (no database required, easy [backup](Backup-and-restore.md))
+- [Configurable](Shaarli-configuration.md) from dialog and configuration file
+- Extensible through third-party [plugins and themes](Community-and-related-software.md)
 
 
-## Screenshots
+### Fast
 
-[![](https://i.imgur.com/8wEBRSG.png)](https://i.imgur.com/WWPfSj0.png) [![](https://i.imgur.com/rrsjWYy.png)](https://i.imgur.com/TZzGHMs.png) [![](https://i.imgur.com/uICDOle.png)](https://i.imgur.com/27wYsbC.png) [![](https://i.imgur.com/KNvFGVB.png)](https://i.imgur.com/0f5faqw.png) [![](https://i.imgur.com/tVvD3gH.png)](https://i.imgur.com/zGF4d6L.jpg) [![](https://i.imgur.com/8iRzHfe.png)](https://i.imgur.com/sfJJ6NT.png) [![](https://i.imgur.com/GjZGvIh.png)](https://i.imgur.com/QsedIuJ.png) [![](https://i.imgur.com/TFZ9PEq.png)](https://i.imgur.com/KdtF8Ll.png) [![](https://i.imgur.com/IvlqXXK.png)](https://i.imgur.com/boaaibC.png) [![](https://i.imgur.com/nlETouG.png)](https://i.imgur.com/Ib9O7n3.png)
+- Fast! Small datastore file, write-once/read-many, served most of the time from OS disk caches (no disk I/O)
+- Stays fast with even tens of thousands shaares!
 
 
+### Self-hosted
 
+- Shaarli is an alternative to commercial services such as StumbleUpon, Delicio.us, Diigo...
+- The data is yours, [import and export](Usage#import-export) it to HTML bookmarksformat compatible with most web browser, and from a variety of formats
+- Shaarli does not send any telemetry/metrics/private information to developers
+- Shaarli is Free and Open-Source software, inspect and change how the program works in the [source code](https://github.com/shaarli/Shaarli)
+- Built-in [Security](dev/Development.md#security) features to help you protect your Shaarli instance
 
 
 ## About
 
-### Shaarli community fork
-
-This friendly fork is maintained by the Shaarli community at <https://github.com/shaarli/Shaarli>
-
-This is a community fork of the original [Shaarli](https://github.com/sebsauvage/Shaarli/) project by [Sébastien Sauvage](http://sebsauvage.net/).
-
-The original project is currently unmaintained, and the developer [has informed us](https://github.com/sebsauvage/Shaarli/issues/191) that he would have no time to work on Shaarli in the near future.
+This [community fork](https://github.com/shaarli/Shaarli) of the original [Shaarli](https://github.com/sebsauvage/Shaarli/) project by [Sébastien Sauvage](http://sebsauvage.net/) (now [unmaintained](https://github.com/sebsauvage/Shaarli/issues/191)) has carried on the work to provide [many patches](https://github.com/shaarli/Shaarli/compare/sebsauvage:master...master) for [bug fixes and enhancements](https://github.com/shaarli/Shaarli/issues?q=is%3Aclosed+) in this repository, and will keep maintaining the project for the foreseeable future, while keeping Shaarli simple and efficient.
 
-The Shaarli community has carried on the work to provide [many
-patches](https://github.com/shaarli/Shaarli/compare/sebsauvage:master...master) for
-[bug fixes and enhancements](https://github.com/shaarli/Shaarli/issues?q=is%3Aclosed+)
-in this repository, and will keep maintaining the project for the foreseeable
-future, while keeping Shaarli simple and efficient.
+The original Shaarli instance is still available [here](https://sebsauvage.net/links/) (+25000 shaares!)
 
 
 ### Contributing and getting help
 
-Feedback is very appreciated!
+Feedback is very appreciated! Feel free to propose solutions to existing problems, help us improve the documentation and translations, and submit pull requests :-)
 
-- If you have any questions or ideas, please join the [chat](https://gitter.im/shaarli/Shaarli) (also reachable via [IRC](https://irc.gitter.im/)), post them in our [general discussion](https://github.com/shaarli/Shaarli/issues/308) or read the current [issues](https://github.com/shaarli/Shaarli/issues).
-- Have a look at the open [issues](https://github.com/shaarli/Shaarli/issues) and [pull requests](https://github.com/shaarli/Shaarli/pulls)
-- If you would like a feature added to Shaarli, check the issues labeled [`feature`](https://github.com/shaarli/Shaarli/labels/feature), [`enhancement`](https://github.com/shaarli/Shaarli/labels/enhancement), and [`plugin`](https://github.com/shaarli/Shaarli/labels/plugin).
-- If you've found a bug, please create a [new issue](https://github.com/shaarli/Shaarli/issues/new).
-- Feel free to propose solutions to existing problems, help us improve the documentation and translations, and submit pull requests :-)
+See [Support](Troubleshooting.md#support) to get in touch with the Shaarli community.
 
 
 ### License
index e8ea4271267fb4f02659b78ebf17295ebc9d73b6..a3de4b1c42424a2fcd25fccc17513b11e8556a5d 100644 (file)
@@ -33,7 +33,7 @@ services:
       traefik.frontend.rule: "Host:${SHAARLI_VIRTUAL_HOST}"
 
   traefik:
-    image: traefik
+    image: traefik:1.7-alpine
     command:
       - "--defaultentrypoints=http,https"
       - "--entrypoints=Name:http Address::80 Redirect.EntryPoint:https"
index fbb2fe64df4eb37b859c9a7896f8210ea84c20de..9a6e3958ca2a571092ae4206178ca6546b8febfc 100644 (file)
@@ -1,8 +1,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: Shaarli\n"
-"POT-Creation-Date: 2020-08-27 12:01+0200\n"
-"PO-Revision-Date: 2020-08-27 12:02+0200\n"
+"POT-Creation-Date: 2020-09-10 16:06+0200\n"
+"PO-Revision-Date: 2020-09-10 16:07+0200\n"
 "Last-Translator: \n"
 "Language-Team: Shaarli\n"
 "Language: fr_FR\n"
@@ -60,16 +60,20 @@ msgid "Automatic"
 msgstr "Automatique"
 
 #: application/Languages.php:182
+msgid "German"
+msgstr "Allemand"
+
+#: application/Languages.php:183
 msgid "English"
 msgstr "Anglais"
 
-#: application/Languages.php:183
+#: application/Languages.php:184
 msgid "French"
 msgstr "Français"
 
-#: application/Languages.php:184
-msgid "German"
-msgstr "Allemand"
+#: application/Languages.php:185
+msgid "Japanese"
+msgstr "Japonais"
 
 #: application/Thumbnailer.php:62
 msgid ""
@@ -103,36 +107,119 @@ msgstr "Mo"
 msgid "GiB"
 msgstr "Go"
 
-#: application/bookmark/BookmarkFileService.php:165
-#: application/bookmark/BookmarkFileService.php:190
-#: application/bookmark/BookmarkFileService.php:215
-#: application/bookmark/BookmarkFileService.php:232
+#: application/bookmark/BookmarkFileService.php:174
+#: application/bookmark/BookmarkFileService.php:199
+#: application/bookmark/BookmarkFileService.php:224
+#: application/bookmark/BookmarkFileService.php:241
 msgid "You're not authorized to alter the datastore"
 msgstr "Vous n'êtes pas autorisé à modifier les données"
 
-#: application/bookmark/BookmarkFileService.php:168
-#: application/bookmark/BookmarkFileService.php:193
-#: application/bookmark/BookmarkFileService.php:235
+#: application/bookmark/BookmarkFileService.php:177
+#: application/bookmark/BookmarkFileService.php:202
+#: application/bookmark/BookmarkFileService.php:244
 msgid "Provided data is invalid"
 msgstr "Les informations fournies ne sont pas valides"
 
-#: application/bookmark/BookmarkFileService.php:196
+#: application/bookmark/BookmarkFileService.php:205
 msgid "This bookmarks already exists"
 msgstr "Ce marque-page existe déjà."
 
 #: application/bookmark/BookmarkInitializer.php:37
-#: application/legacy/LegacyLinkDB.php:266
-msgid "My secret stuff... - Pastebin.com"
-msgstr "Mes trucs secrets... - Pastebin.com"
+msgid "(private bookmark with thumbnail demo)"
+msgstr "(marque page privé avec une miniature)"
 
-#: application/bookmark/BookmarkInitializer.php:39
-#: application/legacy/LegacyLinkDB.php:268
-msgid "Shhhh! I'm a private link only YOU can see. You can delete me too."
+#: application/bookmark/BookmarkInitializer.php:40
+msgid ""
+"Shaarli will automatically pick up the thumbnail for links to a variety of "
+"websites.\n"
+"\n"
+"Explore your new Shaarli instance by trying out controls and menus.\n"
+"Visit the project on [Github](https://github.com/shaarli/Shaarli) or [the "
+"documentation](https://shaarli.readthedocs.io/en/master/) to learn more "
+"about Shaarli.\n"
+"\n"
+"Now you can edit or delete the default shaares.\n"
 msgstr ""
-"Pssst ! Je suis un lien privé que VOUS êtes le seul à voir. Vous pouvez me "
-"supprimer aussi."
+"Shaarli récupérera automatiquement la miniature associée au liens pour de "
+"nombreux sites web.\n"
+"\n"
+"Explorez votre nouvelle instance de Shaarli en essayant les différents "
+"contrôles et menus.\n"
+"Visitez le projet sur [Github](https://github.com/shaarli/Shaarli) ou [la "
+"documentation](https://shaarli.readthedocs.io/en/master/) pour en apprendre "
+"plus sur Shaarli.\n"
+"\n"
+"Maintenant, vous pouvez modifier ou supprimer les shaares créés par défaut.\n"
+
+#: application/bookmark/BookmarkInitializer.php:53
+msgid "Note: Shaare descriptions"
+msgstr "Note : Description des Shaares"
 
-#: application/bookmark/BookmarkInitializer.php:45
+#: application/bookmark/BookmarkInitializer.php:55
+msgid ""
+"Adding a shaare without entering a URL creates a text-only \"note\" post "
+"such as this one.\n"
+"This note is private, so you are the only one able to see it while logged "
+"in.\n"
+"\n"
+"You can use this to keep notes, post articles, code snippets, and much "
+"more.\n"
+"\n"
+"The Markdown formatting setting allows you to format your notes and bookmark "
+"description:\n"
+"\n"
+"### Title headings\n"
+"\n"
+"#### Multiple headings levels\n"
+"  * bullet lists\n"
+"  * _italic_ text\n"
+"  * **bold** text\n"
+"  * ~~strike through~~ text\n"
+"  * `code` blocks\n"
+"  * images\n"
+"  * [links](https://en.wikipedia.org/wiki/Markdown)\n"
+"\n"
+"Markdown also supports tables:\n"
+"\n"
+"| Name    | Type      | Color  | Qty   |\n"
+"| ------- | --------- | ------ | ----- |\n"
+"| Orange  | Fruit     | Orange | 126   |\n"
+"| Apple   | Fruit     | Any    | 62    |\n"
+"| Lemon   | Fruit     | Yellow | 30    |\n"
+"| Carrot  | Vegetable | Red    | 14    |\n"
+msgstr ""
+"Ajouter un shaare sans préciser d'URL créé une « note » textuelle, telle que "
+"celle-ci.\n"
+"Cette note est privée, donc vous êtes seul à pouvoir la voir lorsque vous "
+"êtes connecté.\n"
+"\n"
+"Vous pouvez utiliser cette fonctionnalité pour prendre des notes, publier "
+"des articles, des extraits de code, et bien plus.\n"
+"\n"
+"L'option du formatage par Markdown vous permet de formater vos description "
+"de notes et marque-pages :\n"
+"\n"
+"### Titre d'en-tête\n"
+"\n"
+"#### Sur plusieurs niveaux\n"
+"  * liste à puce\n"
+"  * texte en _italique_\n"
+"  * texte en **gras**\n"
+"  * texte ~~barré~~\n"
+"  * blocs de `code`\n"
+"  * images\n"
+"  * [liens](https://en.wikipedia.org/wiki/Markdown)\n"
+"\n"
+"Markdown supporte aussi les tableaux :\n"
+"\n"
+"| Nom    | Type      | Couleur  | Qte   |\n"
+"| ------- | --------- | ------ | ----- |\n"
+"| Orange  | Fruit     | Orange | 126   |\n"
+"| Pomme   | Fruit     | Multiple    | 62    |\n"
+"| Citron   | Fruit     | Jaune | 30    |\n"
+"| Carotte  | Légume | Orange    | 14    |\n"
+
+#: application/bookmark/BookmarkInitializer.php:89
 #: application/legacy/LegacyLinkDB.php:246
 #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15
 #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:49
@@ -144,26 +231,54 @@ msgstr ""
 "Le gestionnaire de marque-pages personnel, minimaliste, et sans base de "
 "données"
 
-#: application/bookmark/BookmarkInitializer.php:48
-#: application/legacy/LegacyLinkDB.php:249
+#: application/bookmark/BookmarkInitializer.php:92
 msgid ""
-"Welcome to Shaarli! This is your first public bookmark. To edit or delete "
-"me, you must first login.\n"
+"Welcome to Shaarli!\n"
 "\n"
-"To learn how to use Shaarli, consult the link \"Documentation\" at the "
-"bottom of this page.\n"
+"Shaarli allows you to bookmark your favorite pages, and share them with "
+"others or store them privately.\n"
+"You can add a description to your bookmarks, such as this one, and tag "
+"them.\n"
 "\n"
-"You use the community supported version of the original Shaarli project, by "
-"Sebastien Sauvage."
+"Create a new shaare by clicking the `+Shaare` button, or using any of the "
+"recommended tools (browser extension, mobile app, bookmarklet, REST API, "
+"etc.).\n"
+"\n"
+"You can easily retrieve your links, even with thousands of them, using the "
+"internal search engine, or search through tags (e.g. this Shaare is tagged "
+"with `shaarli` and `help`).\n"
+"Hashtags such as #shaarli #help are also supported.\n"
+"You can also filter the available [RSS feed](/feed/atom) and picture wall by "
+"tag or plaintext search.\n"
+"\n"
+"We hope that you will enjoy using Shaarli, maintained with ❤️ by the "
+"community!\n"
+"Feel free to open [an issue](https://github.com/shaarli/Shaarli/issues) if "
+"you have a suggestion or encounter an issue.\n"
 msgstr ""
-"Bienvenue sur Shaarli ! Ceci est votre premier marque-page public. Pour me "
-"modifier ou me supprimer, vous devez d'abord vous connecter.\n"
+"Bienvenue sur Shaarli !\n"
 "\n"
-"Pour apprendre à utiliser Shaarli, consultez le lien « Documentation » en "
-"bas de page.\n"
+"Shaarli vous permet de sauvegarder des marque-pages de vos pages favorites, "
+"et de les partager avec d'autres, ou de les enregistrer en privé.\n"
+"Vous pouvez ajouter une description à vos marque-pages, comme celle-ci, et y "
+"ajouter des tags.\n"
 "\n"
-"Vous utilisez la version supportée par la communauté du projet original "
-"Shaarli de Sébastien Sauvage."
+"Créez un nouveau shaare en cliquant sur le bouton `+Shaare`, ou en utilisant "
+"l'un des outils recommandés (extension de navigateur, application mobile, "
+"bookmarklet, REST API, etc.).\n"
+"\n"
+"Vous pouvez facilement retrouver vos liens, même parmi des milliers, en "
+"utilisant le moteur de recherche interne, ou en filtrant par tags (par "
+"exemple ce Shaare est taggé avec `shaarli` et `help`).\n"
+"Les hashtags comme #shaarli #help sont aussi supportés.\n"
+"Vous pouvez aussi filtrer les [flux RSS](/feed/atom) et [mur d'images]() par "
+"tag ou par texte brut.\n"
+"\n"
+"Nous espérons que vous apprécierez utiliser Shaarli, maintenu avec ❤️ par la "
+"communauté !\n"
+"N'hésitez pas à ouvrir [un ticket (en)](https://github.com/shaarli/Shaarli/"
+"issues) si vous avez une suggestion ou si vous rencontrez un problème.\n"
+" \n"
 
 #: application/bookmark/exception/BookmarkNotFoundException.php:13
 msgid "The link you are trying to reach does not exist or has been deleted."
@@ -489,6 +604,36 @@ msgstr "Vous devez utiliser un entier comme clé."
 msgid "Array offset and link ID must be equal."
 msgstr "La clé du tableau et l'ID du lien doivent être identiques."
 
+#: application/legacy/LegacyLinkDB.php:249
+msgid ""
+"Welcome to Shaarli! This is your first public bookmark. To edit or delete "
+"me, you must first login.\n"
+"\n"
+"To learn how to use Shaarli, consult the link \"Documentation\" at the "
+"bottom of this page.\n"
+"\n"
+"You use the community supported version of the original Shaarli project, by "
+"Sebastien Sauvage."
+msgstr ""
+"Bienvenue sur Shaarli ! Ceci est votre premier marque-page public. Pour me "
+"modifier ou me supprimer, vous devez d'abord vous connecter.\n"
+"\n"
+"Pour apprendre à utiliser Shaarli, consultez le lien « Documentation » en "
+"bas de page.\n"
+"\n"
+"Vous utilisez la version supportée par la communauté du projet original "
+"Shaarli de Sébastien Sauvage."
+
+#: application/legacy/LegacyLinkDB.php:266
+msgid "My secret stuff... - Pastebin.com"
+msgstr "Mes trucs secrets... - Pastebin.com"
+
+#: application/legacy/LegacyLinkDB.php:268
+msgid "Shhhh! I'm a private link only YOU can see. You can delete me too."
+msgstr ""
+"Pssst ! Je suis un lien privé que VOUS êtes le seul à voir. Vous pouvez me "
+"supprimer aussi."
+
 #: application/legacy/LegacyUpdater.php:104
 msgid "Couldn't retrieve updater class methods."
 msgstr "Impossible de récupérer les méthodes de la classe Updater."
@@ -562,7 +707,7 @@ msgstr "Voir sur archive.org"
 msgid "For each link, add an Archive.org icon."
 msgstr "Pour chaque lien, ajoute une icône pour Archive.org."
 
-#: plugins/default_colors/default_colors.php:33
+#: plugins/default_colors/default_colors.php:38
 msgid ""
 "Default colors plugin error: This plugin is active and no custom color is "
 "configured."
@@ -570,21 +715,21 @@ msgstr ""
 "Erreur du plugin default colors : ce plugin est actif et aucune couleur "
 "n'est configurée."
 
-#: plugins/default_colors/default_colors.php:107
+#: plugins/default_colors/default_colors.php:113
 msgid "Override default theme colors. Use any CSS valid color."
 msgstr ""
 "Remplacer les couleurs du thème par défaut. Utiliser n'importe quelle "
 "couleur CSS valide."
 
-#: plugins/default_colors/default_colors.php:108
+#: plugins/default_colors/default_colors.php:114
 msgid "Main color (navbar green)"
 msgstr "Couleur principale (vert de la barre de navigation)"
 
-#: plugins/default_colors/default_colors.php:109
+#: plugins/default_colors/default_colors.php:115
 msgid "Background color (light grey)"
 msgstr "Couleur de fond (gris léger)"
 
-#: plugins/default_colors/default_colors.php:110
+#: plugins/default_colors/default_colors.php:116
 msgid "Dark main color (e.g. visited links)"
 msgstr "Couleur principale sombre (ex : les liens visités)"
 
@@ -1168,23 +1313,23 @@ msgstr "Changer statut épinglé"
 msgid "Sticky"
 msgstr "Épinglé"
 
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:7
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:7
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:5
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:5
 msgid "Filters"
 msgstr "Filtres"
 
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:12
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:12
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:10
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:10
 msgid "Only display private links"
 msgstr "Afficher uniquement les liens privés"
 
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:15
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:15
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:13
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:13
 msgid "Only display public links"
 msgstr "Afficher uniquement les liens publics"
 
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:20
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:20
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:18
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:18
 msgid "Filter untagged links"
 msgstr "Filtrer par liens privés"
 
@@ -1193,17 +1338,17 @@ msgstr "Filtrer par liens privés"
 msgid "Select all"
 msgstr "Tout sélectionner"
 
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:27
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:79
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:27
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:79
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:29
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:89
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:29
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:89
 #: tmp/page.footer.b91ef64efc3688266305ea9b42e5017e.rtpl.php:44
 #: tmp/page.footer.cedf684561d925457130839629000a81.rtpl.php:44
 msgid "Fold all"
 msgstr "Replier tout"
 
-#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:72
-#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:72
+#: tmp/linklist.paging.b91ef64efc3688266305ea9b42e5017e.rtpl.php:76
+#: tmp/linklist.paging.cedf684561d925457130839629000a81.rtpl.php:76
 msgid "Links per page"
 msgstr "Liens par page"
 
@@ -1429,32 +1574,24 @@ msgid "Rename or delete a tag in all links"
 msgstr "Renommer ou supprimer un tag dans tous les liens"
 
 #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:41
-#, fuzzy
-#| msgid ""
-#| "Import Netscape HTML bookmarks (as exported from Firefox, Chrome, Opera, "
-#| "delicious…)"
 msgid ""
 "Import Netscape HTML bookmarks (as exported from Firefox, Chrome, Opera, "
 "delicious...)"
 msgstr ""
 "Importer des marques pages au format Netscape HTML (comme exportés depuis "
-"Firefox, Chrome, Opera, delicious)"
+"Firefox, Chrome, Opera, delicious...)"
 
 #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:42
 msgid "Import links"
 msgstr "Importer des liens"
 
 #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:47
-#, fuzzy
-#| msgid ""
-#| "Export Netscape HTML bookmarks (which can be imported in Firefox, Chrome, "
-#| "Opera, delicious…)"
 msgid ""
 "Export Netscape HTML bookmarks (which can be imported in Firefox, Chrome, "
 "Opera, delicious...)"
 msgstr ""
 "Exporter les marques pages au format Netscape HTML (comme exportés depuis "
-"Firefox, Chrome, Opera, delicious)"
+"Firefox, Chrome, Opera, delicious...)"
 
 #: tmp/tools.b91ef64efc3688266305ea9b42e5017e.rtpl.php:48
 msgid "Export database"
index 869f42de1352eafb5ec95bf44de6ca2c1b29855e..b10397dda2d079cb785caa6fddef262d77331503 100644 (file)
--- a/index.php
+++ b/index.php
@@ -35,6 +35,9 @@ use Slim\App;
 
 $conf = new ConfigManager();
 
+// Manually override root URL for complex server configurations
+define('SHAARLI_ROOT_URL', $conf->get('general.root_url', null));
+
 // In dev mode, throw exception on any warning
 if ($conf->get('dev.debug', false)) {
     // See all errors (for debugging only)
index cee2c5fbddd1c00096cd200df3e5f683a44b5359..2e201d03558cfddd9ada09c3c24514a9e16e88ea 100644 (file)
@@ -15,41 +15,25 @@ site_dir: doc/html
 pages:
 - Home: index.md
 - Setup:
-    - Download and Installation: Download-and-Installation.md
-    - Upgrade and migration: Upgrade-and-migration.md
     - Server configuration: Server-configuration.md
-    - Server security: Server-security.md
+    - Installation: Installation.md
+    - Docker: Docker.md
+    - Reverse Proxy: Reverse-proxy.md
+    - Backup and restore: Backup-and-restore.md
     - Shaarli configuration: Shaarli-configuration.md
     - Plugins: Plugins.md
-- Docker:
-    - Docker 101: docker/docker-101.md
-    - Shaarli images: docker/shaarli-images.md
-    - Reverse proxy configuration: docker/reverse-proxy-configuration.md
-    - Docker resources: docker/resources.md
+    - Upgrade and migration: Upgrade-and-migration.md
 - Usage:
-    - Browsing and searching: Browsing-and-searching.md
-    - Sharing content: Sharing-content.md
-    - RSS feeds: RSS-feeds.md
+    - Usage: Usage.md
     - REST API: REST-API.md
-    - Community & Related software: Community-&-Related-software.md
-- Guides:
-    - Install Shaarli on Debian 9 with Docker: guides/install-shaarli-with-debian9-and-docker.md
-    - Backup, restore, import and export: guides/backup-restore-import-export.md
-    - Various hacks: guides/various-hacks.md
+    - Community and Related software: Community-and-related-software.md
 - Development:
-    - Development guidelines: Development-guidelines.md
-    - Continuous integration tools: Continuous-integration-tools.md
-    - GnuPG signature: GnuPG-signature.md
-    - Directory structure: Directory-structure.md
-    - Link Structure: Link-structure.md
-    - 3rd party libraries: 3rd-party-libraries.md
-    - Plugin System: Plugin-System.md
-    - Release Shaarli: Release-Shaarli.md
-    - Versioning and Branches: Versioning-and-Branches.md
-    - Security: Security.md
-    - Static analysis: Static-analysis.md
-    - Translations: Translations.md
-    - Theming: Theming.md
-    - Unit tests: Unit-tests.md
-- FAQ: FAQ.md
+    - Development: dev/Development.md
+    - Versioning: dev/Versioning.md
+    - GnuPG signature: dev/GnuPG-signature.md
+    - Plugin System: dev/Plugin-system.md
+    - Translations: dev/Translations.md
+    - Release Shaarli: dev/Release-Shaarli.md
+    - Theming: dev/Theming.md
+    - Unit tests: dev/Unit-tests.md
 - Troubleshooting: Troubleshooting.md
index f3d9b51eb2271002df8c617636dab110b011401d..8a24512a4bba538f0a89687bb0a0147b87d65898 100644 (file)
     "purecss": "^1.0.0"
   },
   "devDependencies": {
-    "babel-core": "^6.26.0",
-    "babel-loader": "^7.1.2",
-    "babel-minify-webpack-plugin": "^0.2.0",
-    "babel-preset-env": "^1.6.1",
-    "css-loader": "^0.28.9",
-    "eslint": "^4.16.0",
-    "eslint-config-airbnb-base": "^12.1.0",
-    "eslint-plugin-import": "^2.8.0",
-    "extract-text-webpack-plugin": "^3.0.2",
+    "@babel/core": "^7.11.6",
+    "@babel/preset-env": "^7.11.5",
+    "babel-loader": "^8.1.0",
+    "css-loader": "^4.3.0",
+    "eslint": "^7.9.0",
+    "eslint-config-airbnb-base": "^14.2.0",
+    "eslint-plugin-import": "^2.22.0",
     "file-loader": "^1.1.6",
-    "node-sass": "^4.12.0",
-    "sass-lint": "^1.12.1",
-    "sass-loader": "^6.0.6",
-    "style-loader": "^0.19.1",
-    "url-loader": "^0.6.2",
-    "webpack": "^3.10.0"
+    "mini-css-extract-plugin": "^0.11.2",
+    "sass": "^1.26.11",
+    "sass-loader": "^10.0.2",
+    "stylelint": "^13.7.1",
+    "stylelint-config-standard": "^20.0.0",
+    "stylelint-scss": "^3.18.0",
+    "terser-webpack-plugin": "^4.2.2",
+    "webpack": "^4.44.2",
+    "webpack-cli": "^3.3.12"
   },
   "scripts": {
     "build": "webpack",
index f26e61292cea3c50e44d32e7f7ff408829d9e881..922b5966fe3340b203b8c98cc6f970555e4b43a5 100644 (file)
@@ -20,10 +20,12 @@ function hook_archiveorg_render_linklist($data)
     $path = ($data['_BASE_PATH_'] ?? '') . '/' . PluginManager::$PLUGINS_PATH;
 
     foreach ($data['links'] as &$value) {
-        if ($value['private'] && preg_match('/^\?[a-zA-Z0-9-_@]{6}($|&|#)/', $value['real_url'])) {
+        $isNote = startsWith($value['real_url'], '/shaare/');
+        if ($value['private'] && $isNote) {
             continue;
         }
-        $archive = sprintf($archive_html, $value['url'], $path, t('View on archive.org'));
+        $url = $isNote ? rtrim(index_url($_SERVER), '/') . $value['real_url'] : $value['real_url'];
+        $archive = sprintf($archive_html, $url, $path, t('View on archive.org'));
         $value['link_plugin'][] = $archive;
     }
 
index 16edd9a61e44236b53832ce150a3e1b938c5a4fe..79e7380b66f543ade34bb080e027cba26990a7bf 100644 (file)
@@ -49,7 +49,7 @@ function hook_isso_render_linklist($data, $conf)
         $isso = sprintf($issoHtml, $issoUrl, $issoUrl, $link['id'], $link['id']);
         $data['plugin_end_zone'][] = $isso;
     } else {
-        $button = '<span><a href="?%s#isso-thread">';
+        $button = '<span><a href="'. ($data['_BASE_PATH_'] ?? '') . '/shaare/%s#isso-thread">';
         // For the default theme we use a FontAwesome icon which is better than an image
         if ($conf->get('resource.theme') === 'default') {
             $button .= '<i class="linklist-plugin-icon fa fa-comment"></i>';
index ab4be22a46b5ad2a222fb84e1bae5ca4af40e745..32a94e88080c31849b01e1acdcaa10677363eda2 100644 (file)
@@ -8,22 +8,21 @@ This uses code from https://zaius.github.io/youtube_playlist/ and is currently o
 
 #### Installation and setup
 
-This is a default Shaarli plugin, you just have to enable it. See https://shaarli.readthedocs.io/en/master/Shaarli-configuration/
+This is a default Shaarli plugin, you just have to enable it. See [Shaarli configuration](../../doc/md/Shaarli-configuration.md).
 
 
 #### Troubleshooting
 
-If your server has [Content Security Policy](http://content-security-policy.com/) headers enabled, this may prevent the script from loading fully. You should relax the CSP in your server settings. Example CSP rule for apache2:
-
-In `/etc/apache2/conf-available/shaarli-csp.conf`:
+If your server has [Content Security Policy](http://content-security-policy.com/) headers enabled, this may prevent the script from loading fully. You should relax the CSP in your server settings. Example CSP rule for apache2: 
 
 ```apache
 <Directory /path/to/shaarli>
+    # Required for playvideos plugin
     Header set Content-Security-Policy "script-src 'self' 'unsafe-inline' https://www.youtube.com https://s.ytimg.com 'unsafe-eval'"
 </Directory>
 ```
 
-Then run `a2enconf shaarli-csp; service apache2 reload`
+You may place the `Header` directive in the `<Directory...` section of your [webserver configuration](../../doc/md/Server-configuration.md)/virtualhost file, or write the above snippet to `/etc/apache2/conf-available/shaarli-csp.conf`; then run `a2enconf shaarli-csp; service apache2 reload`.
 
 ### License
 ```
index 3b5dae344dd63c3b688fc2d40ee8ff2af99e8f09..95499e39f5a9618cfec8bcb4f0a28ed8922537ca 100644 (file)
@@ -42,7 +42,7 @@ function hook_qrcode_render_linklist($data)
 function hook_qrcode_render_footer($data)
 {
     if ($data['_PAGE_'] == TemplatePage::LINKLIST) {
-        $data['js_files'][] =  PluginManager::$PLUGINS_PATH . '/qrcode/shaarli-qrcode.js';
+        $data['js_files'][] = PluginManager::$PLUGINS_PATH . '/qrcode/shaarli-qrcode.js';
     }
 
     return $data;
index 15388970a0b0680e4a2e0ecb7fbf5d7d6bb2d90d..a232b351f4cfdae5c63c4d31553f055500a4111b 100644 (file)
@@ -8,7 +8,7 @@ require_once 'tests/utils/FakeApplicationUtils.php';
 /**
  * Unitary tests for Shaarli utilities
  */
-class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
+class ApplicationUtilsTest extends \Shaarli\TestCase
 {
     protected static $testUpdateFile = 'sandbox/update.txt';
     protected static $testVersion = '0.5.0';
@@ -17,7 +17,7 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset test data for each test
      */
-    public function setUp()
+    protected function setUp(): void
     {
         FakeApplicationUtils::$VERSION_CODE = '';
         if (file_exists(self::$testUpdateFile)) {
@@ -28,7 +28,7 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Remove test version file if it exists
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         if (is_file('sandbox/version.php')) {
             unlink('sandbox/version.php');
@@ -144,11 +144,12 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test update checks - invalid Git branch
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid branch selected for updates/
      */
     public function testCheckUpdateInvalidGitBranch()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Invalid branch selected for updates/');
+
         ApplicationUtils::checkUpdate('', 'null', 0, true, true, 'unstable');
     }
 
@@ -260,21 +261,23 @@ class ApplicationUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Check a unsupported PHP version
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Your PHP version is obsolete/
      */
     public function testCheckSupportedPHPVersion51()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Your PHP version is obsolete/');
+
         $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.1.0'));
     }
 
     /**
      * Check another unsupported PHP version
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Your PHP version is obsolete/
      */
     public function testCheckSupportedPHPVersion52()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Your PHP version is obsolete/');
+
         $this->assertTrue(ApplicationUtils::checkPHPVersion('5.3', '5.2'));
     }
 
index 57719175542c3562af141c0658a9b28e1ba96dcb..9163bdf1face0b250ad801b13de5cd96385507a5 100644 (file)
@@ -9,7 +9,7 @@ use Exception;
  *
  * Test file utility class.
  */
-class FileUtilsTest extends \PHPUnit\Framework\TestCase
+class FileUtilsTest extends \Shaarli\TestCase
 {
     /**
      * @var string Test file path.
@@ -19,7 +19,7 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
     /**
      * Delete test file after every test.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$file);
     }
@@ -49,12 +49,12 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * File not writable: raise an exception.
-     *
-     * @expectedException Shaarli\Exceptions\IOException
-     * @expectedExceptionMessage Error accessing "sandbox/flat.db"
      */
     public function testWriteWithoutPermission()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessage('Error accessing "sandbox/flat.db"');
+
         touch(self::$file);
         chmod(self::$file, 0440);
         FileUtils::writeFlatDB(self::$file, null);
@@ -62,23 +62,23 @@ class FileUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Folder non existent: raise an exception.
-     *
-     * @expectedException Shaarli\Exceptions\IOException
-     * @expectedExceptionMessage Error accessing "nopefolder"
      */
     public function testWriteFolderDoesNotExist()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessage('Error accessing "nopefolder"');
+
         FileUtils::writeFlatDB('nopefolder/file', null);
     }
 
     /**
      * Folder non writable: raise an exception.
-     *
-     * @expectedException Shaarli\Exceptions\IOException
-     * @expectedExceptionMessage Error accessing "sandbox"
      */
     public function testWriteFolderPermission()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessage('Error accessing "sandbox"');
+
         chmod(dirname(self::$file), 0555);
         try {
             FileUtils::writeFlatDB(self::$file, null);
index 7189c3a99fb171dd436834252b7243eaa59a3d23..6dc0e5b7aa112e19f3dd7cbc6f820356885f3088 100644 (file)
@@ -3,10 +3,9 @@
 namespace Shaarli;
 
 use DateTime;
-use Exception;
 use Shaarli\Bookmark\Bookmark;
 
-class HistoryTest extends \PHPUnit\Framework\TestCase
+class HistoryTest extends \Shaarli\TestCase
 {
     /**
      * @var string History file path
@@ -16,7 +15,7 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
     /**
      * Delete history file.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$historyFilePath)) {
             unlink(self::$historyFilePath);
@@ -44,12 +43,12 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Not writable history file: raise an exception.
-     *
-     * @expectedException Exception
-     * @expectedExceptionMessage History file isn't readable or writable
      */
     public function testConstructNotWritable()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('History file isn\'t readable or writable');
+
         touch(self::$historyFilePath);
         chmod(self::$historyFilePath, 0440);
         $history = new History(self::$historyFilePath);
@@ -58,12 +57,12 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Not parsable history file: raise an exception.
-     *
-     * @expectedException Exception
-     * @expectedExceptionMessageRegExp /Could not parse history file/
      */
     public function testConstructNotParsable()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Could not parse history file/');
+
         file_put_contents(self::$historyFilePath, 'not parsable');
         $history = new History(self::$historyFilePath);
         // gzinflate generates a warning
index de83f2913707aef08f52ff08474186e38210c9a8..ce24c160728a833b7dc750d8e5c568c9a07a9206 100644 (file)
@@ -7,7 +7,7 @@ use Shaarli\Config\ConfigManager;
 /**
  * Class LanguagesTest.
  */
-class LanguagesTest extends \PHPUnit\Framework\TestCase
+class LanguagesTest extends \Shaarli\TestCase
 {
     /**
      * @var string Config file path (without extension).
@@ -22,7 +22,7 @@ class LanguagesTest extends \PHPUnit\Framework\TestCase
     /**
      *
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager(self::$configFile);
     }
index a5d5dbe988ea22ad525ed74a71b5c3d421c2d7ec..efef5e8746ed2b165d4902a1877a550cc007b462 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+
 namespace Shaarli\Plugin;
 
 use Shaarli\Config\ConfigManager;
@@ -6,7 +7,7 @@ use Shaarli\Config\ConfigManager;
 /**
  * Unit tests for Plugins
  */
-class PluginManagerTest extends \PHPUnit\Framework\TestCase
+class PluginManagerTest extends \Shaarli\TestCase
 {
     /**
      * Path to tests plugin.
@@ -41,17 +42,31 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
 
         $this->assertTrue(function_exists('hook_test_random'));
 
-        $data = array(0 => 'woot');
+        $data = [0 => 'woot'];
         $this->pluginManager->executeHooks('random', $data);
-        $this->assertEquals('woot', $data[1]);
 
-        $data = array(0 => 'woot');
+        static::assertCount(2, $data);
+        static::assertSame('woot', $data[1]);
+
+        $data = [0 => 'woot'];
         $this->pluginManager->executeHooks('random', $data, array('target' => 'test'));
-        $this->assertEquals('page test', $data[1]);
 
-        $data = array(0 => 'woot');
+        static::assertCount(2, $data);
+        static::assertSame('page test', $data[1]);
+
+        $data = [0 => 'woot'];
         $this->pluginManager->executeHooks('random', $data, array('loggedin' => true));
-        $this->assertEquals('loggedin', $data[1]);
+
+        static::assertCount(2, $data);
+        static::assertEquals('loggedin', $data[1]);
+
+        $data = [0 => 'woot'];
+        $this->pluginManager->executeHooks('random', $data, array('loggedin' => null));
+
+        static::assertCount(3, $data);
+        static::assertEquals('loggedin', $data[1]);
+        static::assertArrayHasKey(2, $data);
+        static::assertNull($data[2]);
     }
 
     /**
@@ -67,8 +82,8 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
         $data = [];
         $this->pluginManager->executeHooks('error', $data);
 
-        $this->assertSame(
-            'test [plugin incompatibility]: Class \'Unknown\' not found',
+        $this->assertRegExp(
+            '/test \[plugin incompatibility\]: Class [\'"]Unknown[\'"] not found/',
             $this->pluginManager->getErrors()[0]
         );
     }
@@ -78,8 +93,8 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
      */
     public function testPluginNotFound(): void
     {
-        $this->pluginManager->load(array());
-        $this->pluginManager->load(array('nope', 'renope'));
+        $this->pluginManager->load([]);
+        $this->pluginManager->load(['nope', 'renope']);
         $this->addToAssertionCount(1);
     }
 
@@ -89,18 +104,18 @@ class PluginManagerTest extends \PHPUnit\Framework\TestCase
     public function testGetPluginsMeta(): void
     {
         PluginManager::$PLUGINS_PATH = self::$pluginPath;
-        $this->pluginManager->load(array(self::$pluginName));
+        $this->pluginManager->load([self::$pluginName]);
 
-        $expectedParameters = array(
-            'pop' => array(
+        $expectedParameters = [
+            'pop' => [
                 'value' => '',
                 'desc'  => 'pop description',
-            ),
-            'hip' => array(
+            ],
+            'hip' => [
                 'value' => '',
                 'desc' => '',
-            ),
-        );
+            ],
+        ];
         $meta = $this->pluginManager->getPluginsMeta();
         $this->assertEquals('test plugin', $meta[self::$pluginName]['description']);
         $this->assertEquals($expectedParameters, $meta[self::$pluginName]['parameters']);
diff --git a/tests/TestCase.php b/tests/TestCase.php
new file mode 100644 (file)
index 0000000..781e7aa
--- /dev/null
@@ -0,0 +1,77 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli;
+
+/**
+ * Helper class extending \PHPUnit\Framework\TestCase.
+ * Used to make Shaarli UT run on multiple versions of PHPUnit.
+ */
+class TestCase extends \PHPUnit\Framework\TestCase
+{
+    /**
+     * expectExceptionMessageRegExp has been removed and replaced by expectExceptionMessageMatches in PHPUnit 9.
+     */
+    public function expectExceptionMessageRegExp(string $regularExpression): void
+    {
+        if (method_exists($this, 'expectExceptionMessageMatches')) {
+            $this->expectExceptionMessageMatches($regularExpression);
+        } else {
+            parent::expectExceptionMessageRegExp($regularExpression);
+        }
+    }
+
+    /**
+     * assertContains is now used for iterable, strings should use assertStringContainsString
+     */
+    public function assertContainsPolyfill($expected, $actual, string $message = ''): void
+    {
+        if (is_string($actual) && method_exists($this, 'assertStringContainsString')) {
+            static::assertStringContainsString($expected, $actual, $message);
+        } else {
+            static::assertContains($expected, $actual, $message);
+        }
+    }
+
+    /**
+     * assertNotContains is now used for iterable, strings should use assertStringNotContainsString
+     */
+    public function assertNotContainsPolyfill($expected, $actual, string $message = ''): void
+    {
+        if (is_string($actual) && method_exists($this, 'assertStringNotContainsString')) {
+            static::assertStringNotContainsString($expected, $actual, $message);
+        } else {
+            static::assertNotContains($expected, $actual, $message);
+        }
+    }
+
+    /**
+     * assertFileNotExists has been renamed in assertFileDoesNotExist
+     */
+    public static function assertFileNotExists(string $filename, string $message = ''): void
+    {
+        if (method_exists(TestCase::class, 'assertFileDoesNotExist')) {
+            static::assertFileDoesNotExist($filename, $message);
+        } else {
+            parent::assertFileNotExists($filename, $message);
+        }
+    }
+
+    /**
+     * assertRegExp has been renamed in assertMatchesRegularExpression
+     */
+    public static function assertRegExp(string $pattern, string $string, string $message = ''): void
+    {
+        if (method_exists(TestCase::class, 'assertMatchesRegularExpression')) {
+            static::assertMatchesRegularExpression($pattern, $string, $message);
+        } else {
+            parent::assertRegExp($pattern, $string, $message);
+        }
+    }
+
+    public function isInTestsContext(): bool
+    {
+        return true;
+    }
+}
index c01849f7f089e45e1ca17af6dcb0ee0a3c2e5daf..70519aca066892d04c6dee3c84a18db34ec536de 100644 (file)
@@ -2,7 +2,6 @@
 
 namespace Shaarli;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use WebThumbnailer\Application\ConfigManager as WTConfigManager;
 
@@ -30,7 +29,7 @@ class ThumbnailerTest extends TestCase
      */
     protected $conf;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('thumbnails.mode', Thumbnailer::MODE_ALL);
@@ -43,7 +42,7 @@ class ThumbnailerTest extends TestCase
         WTConfigManager::addFile('tests/utils/config/wt.json');
     }
 
-    public function tearDown()
+    protected function tearDown(): void
     {
         $this->rrmdirContent('sandbox/');
     }
index 02bf060f34a0a7a1be177b2ab96d10316c73b869..77862855e77743c16fef50630d82856741badb5d 100644 (file)
@@ -8,14 +8,14 @@ require_once 'application/TimeZone.php';
 /**
  * Unitary tests for timezone utilities
  */
-class TimeZoneTest extends PHPUnit\Framework\TestCase
+class TimeZoneTest extends \Shaarli\TestCase
 {
     /**
      * @var array of timezones
      */
     protected $installedTimezones;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->installedTimezones = [
             'Antarctica/Syowa',
index 26d2a6b823170d913be90f3372f220863d8827ca..6e787d7f110f377ca7f83edb3114f21e351910a8 100644 (file)
@@ -10,7 +10,7 @@ require_once 'application/Languages.php';
 /**
  * Unitary tests for Shaarli utilities
  */
-class UtilsTest extends PHPUnit\Framework\TestCase
+class UtilsTest extends \Shaarli\TestCase
 {
     // Log file
     protected static $testLogFile = 'tests.log';
@@ -26,7 +26,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase
     /**
      * Assign reference data
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$defaultTimeZone = date_default_timezone_get();
         // Timezone without DST for test consistency
@@ -36,7 +36,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase
     /**
      * Reset the timezone
      */
-    public static function tearDownAfterClass()
+    public static function tearDownAfterClass(): void
     {
         date_default_timezone_set(self::$defaultTimeZone);
     }
@@ -44,7 +44,7 @@ class UtilsTest extends PHPUnit\Framework\TestCase
     /**
      * Resets test data before each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testLogFile)) {
             unlink(self::$testLogFile);
index df2fb33a7183e306b7bc53344633d93f15003f5b..86700840b35dfc03ef75e052e0365b4e8ee89e29 100644 (file)
@@ -18,7 +18,7 @@ use Slim\Http\Response;
  *
  * @package Api
  */
-class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
+class ApiMiddlewareTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -26,7 +26,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
     protected static $testDatastore = 'sandbox/datastore.php';
 
     /**
-     * @var \ConfigManager instance
+     * @var ConfigManager instance
      */
     protected $conf;
 
@@ -43,7 +43,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('api.secret', 'NapoleonWasALizard');
@@ -61,11 +61,58 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
 
+    /**
+     * Invoke the middleware with a valid token
+     */
+    public function testInvokeMiddlewareWithValidToken(): void
+    {
+        $next = function (Request $request, Response $response): Response {
+            return $response;
+        };
+        $mw = new ApiMiddleware($this->container);
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'GET',
+            'REQUEST_URI' => '/echo',
+            'HTTP_AUTHORIZATION'=> 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard'),
+        ]);
+        $request = Request::createFromEnvironment($env);
+        $response = new Response();
+        /** @var Response $response */
+        $response = $mw($request, $response, $next);
+
+        $this->assertEquals(200, $response->getStatusCode());
+    }
+
+    /**
+     * Invoke the middleware with a valid token
+     * Using specific Apache CGI redirected authorization.
+     */
+    public function testInvokeMiddlewareWithValidTokenFromRedirectedHeader(): void
+    {
+        $next = function (Request $request, Response $response): Response {
+            return $response;
+        };
+
+        $token = 'Bearer ' . ApiUtilsTest::generateValidJwtToken('NapoleonWasALizard');
+        $this->container->environment['REDIRECT_HTTP_AUTHORIZATION'] = $token;
+        $mw = new ApiMiddleware($this->container);
+        $env = Environment::mock([
+            'REQUEST_METHOD' => 'GET',
+            'REQUEST_URI' => '/echo',
+        ]);
+        $request = Request::createFromEnvironment($env);
+        $response = new Response();
+        /** @var Response $response */
+        $response = $mw($request, $response, $next);
+
+        $this->assertEquals(200, $response->getStatusCode());
+    }
+
     /**
      * Invoke the middleware with the API disabled:
      * should return a 401 error Unauthorized.
@@ -109,7 +156,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: API is disabled', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -132,7 +179,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: JWT token not provided', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -157,7 +204,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: Token secret must be set in Shaarli\'s administration', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -180,7 +227,7 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: Invalid JWT header', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 
     /**
@@ -206,6 +253,6 @@ class ApiMiddlewareTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(401, $response->getStatusCode());
         $body = json_decode((string) $response->getBody());
         $this->assertEquals('Not authorized: Malformed JWT token', $body->message);
-        $this->assertContains('ApiAuthorizationException', $body->stacktrace);
+        $this->assertContainsPolyfill('ApiAuthorizationException', $body->stacktrace);
     }
 }
index 7efec9bb98f6aa74bea0b2d572e7142bb94ad7a9..7a143859529b30b9de9fe35b183925b6c58bd82d 100644 (file)
@@ -8,12 +8,12 @@ use Shaarli\Http\Base64Url;
 /**
  * Class ApiUtilsTest
  */
-class ApiUtilsTest extends \PHPUnit\Framework\TestCase
+class ApiUtilsTest extends \Shaarli\TestCase
 {
     /**
      * Force the timezone for ISO datetimes.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         date_default_timezone_set('UTC');
     }
@@ -66,143 +66,143 @@ class ApiUtilsTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test validateJwtToken() with a malformed JWT token.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformed()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = 'ABC.DEF';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with an empty JWT token.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformedEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = false;
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token without header.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformedEmptyHeader()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = '.payload.signature';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token without payload
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Malformed JWT token
      */
     public function testValidateJwtTokenMalformedEmptyPayload()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Malformed JWT token');
+
         $token = 'header..signature';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with an empty signature.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT signature
      */
     public function testValidateJwtTokenInvalidSignatureEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT signature');
+
         $token = 'header.payload.';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with an invalid signature.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT signature
      */
     public function testValidateJwtTokenInvalidSignature()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT signature');
+
         $token = 'header.payload.nope';
         ApiUtils::validateJwtToken($token, 'foo');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with a signature generated with the wrong API secret.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT signature
      */
     public function testValidateJwtTokenInvalidSignatureSecret()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT signature');
+
         ApiUtils::validateJwtToken(self::generateValidJwtToken('foo'), 'bar');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with a an invalid header (not JSON).
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT header
      */
     public function testValidateJwtTokenInvalidHeader()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT header');
+
         $token = $this->generateCustomJwtToken('notJSON', '{"JSON":1}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with a JWT token with a an invalid payload (not JSON).
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT payload
      */
     public function testValidateJwtTokenInvalidPayload()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT payload');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', 'notJSON', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with a JWT token without issued time.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT issued time
      */
     public function testValidateJwtTokenInvalidTimeEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT issued time');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', '{"JSON":1}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with an expired JWT token.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT issued time
      */
     public function testValidateJwtTokenInvalidTimeExpired()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT issued time');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() - 600) . '}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
 
     /**
      * Test validateJwtToken() with a JWT token issued in the future.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiAuthorizationException
-     * @expectedExceptionMessage Invalid JWT issued time
      */
     public function testValidateJwtTokenInvalidTimeFuture()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiAuthorizationException::class);
+        $this->expectExceptionMessage('Invalid JWT issued time');
+
         $token = $this->generateCustomJwtToken('{"JSON":1}', '{"iat":' . (time() + 60) . '}', 'secret');
         ApiUtils::validateJwtToken($token, 'secret');
     }
index f4d3b646224d166ecc9412433a709d393741561b..84f8716e1308e92a70cdd530b4c0358570ff4ddd 100644 (file)
@@ -11,7 +11,7 @@ use Slim\Http\Response;
 
 require_once 'tests/utils/ReferenceHistory.php';
 
-class HistoryTest extends \PHPUnit\Framework\TestCase
+class HistoryTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -41,7 +41,7 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->refHistory = new \ReferenceHistory();
@@ -57,7 +57,7 @@ class HistoryTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testHistory);
     }
index b5c938e1bf9f82517596de57129d28139d0eaf8a..1598e1e8ac8e8edec612eb79cbe969ed22f1676f 100644 (file)
@@ -1,10 +1,10 @@
 <?php
 namespace Shaarli\Api\Controllers;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 use Slim\Container;
 use Slim\Http\Environment;
 use Slim\Http\Request;
@@ -47,7 +47,7 @@ class InfoTest extends TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -67,7 +67,7 @@ class InfoTest extends TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
index 6c2b36988c6741128934c3538d14b1496b3cc7b5..cf9464f07877e1613ae0b5704ed2a523da23c497 100644 (file)
@@ -11,7 +11,7 @@ use Slim\Http\Environment;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
-class DeleteLinkTest extends \PHPUnit\Framework\TestCase
+class DeleteLinkTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -56,7 +56,7 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -78,7 +78,7 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
@@ -113,11 +113,11 @@ class DeleteLinkTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test DELETE link endpoint: reach not existing ID.
-     *
-     * @expectedException \Shaarli\Api\Exceptions\ApiLinkNotFoundException
      */
     public function testDeleteLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
+
         $id = -1;
         $this->assertFalse($this->bookmarkService->exists($id));
         $env = Environment::mock([
index 8bb81dc8f8f1a7c313da25d9c8ce54c1c2dd9d25..99dc606fbf95c1d6bae7ef716a4fa335a55491e4 100644 (file)
@@ -20,7 +20,7 @@ use Slim\Http\Response;
  *
  * @package Shaarli\Api\Controllers
  */
-class GetLinkIdTest extends \PHPUnit\Framework\TestCase
+class GetLinkIdTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -55,7 +55,7 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -74,7 +74,7 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
@@ -120,12 +120,12 @@ class GetLinkIdTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test basic getLink service: get non existent link => ApiLinkNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
-     * @expectedExceptionMessage Link not found
      */
     public function testGetLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
+        $this->expectExceptionMessage('Link not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'GET',
         ]);
index d02e6fad8284511a3a659402c9d0e79a30b2cdda..ca1bfc6362d550de19805938f397938344f409f7 100644 (file)
@@ -20,7 +20,7 @@ use Slim\Http\Response;
  *
  * @package Shaarli\Api\Controllers
  */
-class GetLinksTest extends \PHPUnit\Framework\TestCase
+class GetLinksTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -55,7 +55,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -74,7 +74,7 @@ class GetLinksTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
index 4e791a04191472ae33c67c175c5f51a977c0d4dd..20694571de7857415e71c15fd2cb09d8fc6593ef 100644 (file)
@@ -2,11 +2,11 @@
 
 namespace Shaarli\Api\Controllers;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 use Slim\Container;
 use Slim\Http\Environment;
 use Slim\Http\Request;
@@ -70,7 +70,7 @@ class PostLinkTest extends TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -107,7 +107,7 @@ class PostLinkTest extends TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
@@ -160,6 +160,8 @@ class PostLinkTest extends TestCase
             'description' => 'shaare description',
             'tags' => ['one', 'two'],
             'private' => true,
+            'created' => '2015-05-05T12:30:00+03:00',
+            'updated' => '2016-06-05T14:32:10+03:00',
         ];
         $env = Environment::mock([
             'REQUEST_METHOD' => 'POST',
@@ -181,10 +183,8 @@ class PostLinkTest extends TestCase
         $this->assertEquals($link['description'], $data['description']);
         $this->assertEquals($link['tags'], $data['tags']);
         $this->assertEquals(true, $data['private']);
-        $this->assertTrue(
-            new \DateTime('2 seconds ago') < \DateTime::createFromFormat(\DateTime::ATOM, $data['created'])
-        );
-        $this->assertEquals('', $data['updated']);
+        $this->assertSame($link['created'], $data['created']);
+        $this->assertSame($link['updated'], $data['updated']);
     }
 
     /**
index 302cac0fb78a7f42205d2a1f8188b8a56644dee9..a2e87c5986304938662c33d05d21d7cbb313f60e 100644 (file)
@@ -12,7 +12,7 @@ use Slim\Http\Environment;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
-class PutLinkTest extends \PHPUnit\Framework\TestCase
+class PutLinkTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -62,7 +62,7 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -91,7 +91,7 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
@@ -218,12 +218,12 @@ class PutLinkTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test link update on non existent link => ApiLinkNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiLinkNotFoundException
-     * @expectedExceptionMessage Link not found
      */
     public function testGetLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiLinkNotFoundException::class);
+        $this->expectExceptionMessage('Link not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'PUT',
         ]);
index c67488720b7b2617f8b6b509d1eef4036ed3dd58..1326eb47aa7751f20885cb37df764f860097e0f7 100644 (file)
@@ -12,7 +12,7 @@ use Slim\Http\Environment;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
-class DeleteTagTest extends \PHPUnit\Framework\TestCase
+class DeleteTagTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -57,7 +57,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -79,7 +79,7 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
@@ -150,12 +150,12 @@ class DeleteTagTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test DELETE tag endpoint: reach not existing tag.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException
-     * @expectedExceptionMessage Tag not found
      */
     public function testDeleteLink404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
+        $this->expectExceptionMessage('Tag not found');
+
         $tagName = 'nopenope';
         $tags = $this->bookmarkService->bookmarksCountPerTag();
         $this->assertFalse(isset($tags[$tagName]));
index b9a81f9bd9514ada7352326910a2ec1cc3639a41..9c05954b4e8131f4a22664f59761cb40ee6f1324 100644 (file)
@@ -18,7 +18,7 @@ use Slim\Http\Response;
  *
  * @package Shaarli\Api\Controllers
  */
-class GetTagNameTest extends \PHPUnit\Framework\TestCase
+class GetTagNameTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -53,7 +53,7 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase
     /**
      * Before each test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -72,7 +72,7 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase
     /**
      * After each test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
@@ -117,12 +117,12 @@ class GetTagNameTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test basic getTag service: get non existent tag => ApiTagNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException
-     * @expectedExceptionMessage Tag not found
      */
     public function testGetTag404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
+        $this->expectExceptionMessage('Tag not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'GET',
         ]);
index 53a3326d58fa0d97d51631bca83859c6cda749d9..3459fdfae361deb737f9e40786e6102a367d223b 100644 (file)
@@ -17,7 +17,7 @@ use Slim\Http\Response;
  *
  * @package Shaarli\Api\Controllers
  */
-class GetTagsTest extends \PHPUnit\Framework\TestCase
+class GetTagsTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -57,7 +57,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -78,7 +78,7 @@ class GetTagsTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
     }
index 2a3cc15a0d05e1ff5c21f2c6837cc222572cdbda..74edde787b745dbddeda6308e51d94c8bd8df61f 100644 (file)
@@ -12,7 +12,7 @@ use Slim\Http\Environment;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
-class PutTagTest extends \PHPUnit\Framework\TestCase
+class PutTagTest extends \Shaarli\TestCase
 {
     /**
      * @var string datastore to test write operations
@@ -62,7 +62,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
     /**
      * Before every test, instantiate a new Api with its config, plugins and bookmarks.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
         $this->conf->set('resource.datastore', self::$testDatastore);
@@ -84,7 +84,7 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
     /**
      * After every test, remove the test datastore.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$testDatastore);
         @unlink(self::$testHistory);
@@ -159,12 +159,12 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test tag update with an empty new tag name => ApiBadParametersException
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiBadParametersException
-     * @expectedExceptionMessage New tag name is required in the request body
      */
     public function testPutTagEmpty()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiBadParametersException::class);
+        $this->expectExceptionMessage('New tag name is required in the request body');
+
         $tagName = 'gnu';
         $newName = '';
 
@@ -194,12 +194,12 @@ class PutTagTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test tag update on non existent tag => ApiTagNotFoundException.
-     *
-     * @expectedException Shaarli\Api\Exceptions\ApiTagNotFoundException
-     * @expectedExceptionMessage Tag not found
      */
     public function testPutTag404()
     {
+        $this->expectException(\Shaarli\Api\Exceptions\ApiTagNotFoundException::class);
+        $this->expectExceptionMessage('Tag not found');
+
         $env = Environment::mock([
             'REQUEST_METHOD' => 'PUT',
         ]);
index 0f8f04c5ad2d9e7e5aab348c4704f764f7fdacda..ebed9bfcaf2d071faa25e8e05e6e404d1f0f5d38 100644 (file)
@@ -2,10 +2,7 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
-use Shaarli\Bookmark\Exception\InvalidBookmarkException;
-use Shaarli\Config\ConfigManager;
-use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkArrayTest
@@ -47,22 +44,22 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: wrong type
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryInstance()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $array[] = 'nope';
     }
 
     /**
      * Test adding a bad entry: no id
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryNoId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = new Bookmark();
         $array[] = $bookmark;
@@ -70,11 +67,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: no url
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryNoUrl()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId(11);
         $array[] = $bookmark;
@@ -82,11 +79,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: invalid offset
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryOffset()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId(11);
         $bookmark->validate();
@@ -95,11 +92,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: invalid ID type
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryIdType()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId('nope');
         $bookmark->validate();
@@ -108,11 +105,11 @@ class BookmarkArrayTest extends TestCase
 
     /**
      * Test adding a bad entry: ID/offset not consistent
-     *
-     * @expectedException Shaarli\Bookmark\Exception\InvalidBookmarkException
      */
     public function testArrayAccessAddBadEntryIdOffset()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\InvalidBookmarkException::class);
+
         $array = new BookmarkArray();
         $bookmark = (new Bookmark())->setId(11);
         $bookmark->validate();
index 7b1906d3fd76a324a30667cab912f56cac6f4baa..c399822b5801520b78c511d91cff5d312ba2b693 100644 (file)
@@ -6,7 +6,6 @@
 namespace Shaarli\Bookmark;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use ReferenceLinkDB;
 use ReflectionClass;
 use Shaarli;
@@ -14,6 +13,7 @@ use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Formatter\BookmarkMarkdownFormatter;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Unitary tests for LegacyLinkDBTest
@@ -66,7 +66,7 @@ class BookmarkFileServiceTest extends TestCase
      *
      * Resets test data for each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
@@ -134,11 +134,11 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test get() method for an undefined bookmark
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testGetUndefined()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $this->privateLinkDB->get(666);
     }
 
@@ -230,13 +230,13 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test add() method for a bookmark without any field set and without writing the data store
-     *
-     * @expectedExceptionMessage Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testAddMinimalNoWrite()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
-        $this->privateLinkDB->add($bookmark);
+        $this->privateLinkDB->add($bookmark, false);
 
         $bookmark = $this->privateLinkDB->get(43);
         $this->assertEquals(43, $bookmark->getId());
@@ -249,34 +249,34 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test add() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testAddLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $this->publicLinkDB->add(new Bookmark());
     }
 
     /**
      * Test add() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testAddNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->add(['title' => 'hi!']);
     }
 
     /**
      * Test add() method with a Bookmark already containing an ID
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage This bookmarks already exists
      */
     public function testAddWithId()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('This bookmarks already exists');
+
         $bookmark = new Bookmark();
         $bookmark->setId(43);
         $this->privateLinkDB->add($bookmark);
@@ -397,44 +397,44 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test set() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testSetLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $this->publicLinkDB->set(new Bookmark());
     }
 
     /**
      * Test set() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testSetNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->set(['title' => 'hi!']);
     }
 
     /**
      * Test set() method with a Bookmark without an ID defined.
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testSetWithoutId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
         $this->privateLinkDB->set($bookmark);
     }
 
     /**
      * Test set() method with a Bookmark with an unknow ID
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testSetWithUnknownId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
         $bookmark->setId(666);
         $this->privateLinkDB->set($bookmark);
@@ -481,23 +481,23 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test addOrSet() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testAddOrSetLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $this->publicLinkDB->addOrSet(new Bookmark());
     }
 
     /**
      * Test addOrSet() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testAddOrSetNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->addOrSet(['title' => 'hi!']);
     }
 
@@ -524,11 +524,11 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test remove() method with an existing Bookmark
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testRemoveExisting()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = $this->privateLinkDB->get(42);
         $this->privateLinkDB->remove($bookmark);
 
@@ -548,34 +548,34 @@ class BookmarkFileServiceTest extends TestCase
 
     /**
      * Test remove() method while logged out
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage You're not authorized to alter the datastore
      */
     public function testRemoveLoggedOut()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('You\'re not authorized to alter the datastore');
+
         $bookmark = $this->privateLinkDB->get(42);
         $this->publicLinkDB->remove($bookmark);
     }
 
     /**
      * Test remove() method with an entry which is not a bookmark instance
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessage Provided data is invalid
      */
     public function testRemoveNotABookmark()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessage('Provided data is invalid');
+
         $this->privateLinkDB->remove(['title' => 'hi!']);
     }
 
     /**
      * Test remove() method with a Bookmark with an unknown ID
-     *
-     * @expectedException Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testRemoveWithUnknownId()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $bookmark = new Bookmark();
         $bookmark->setId(666);
         $this->privateLinkDB->remove($bookmark);
@@ -615,14 +615,18 @@ class BookmarkFileServiceTest extends TestCase
     {
         $dbSize = $this->privateLinkDB->count();
         $this->privateLinkDB->initialize();
-        $this->assertEquals($dbSize + 2, $this->privateLinkDB->count());
-        $this->assertEquals(
-            'My secret stuff... - Pastebin.com',
-            $this->privateLinkDB->get(43)->getTitle()
+        $this->assertEquals($dbSize + 3, $this->privateLinkDB->count());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $this->privateLinkDB->get(43)->getDescription()
         );
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $this->privateLinkDB->get(44)->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $this->privateLinkDB->get(44)->getDescription()
+        );
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $this->privateLinkDB->get(45)->getDescription()
         );
     }
 
@@ -631,15 +635,14 @@ class BookmarkFileServiceTest extends TestCase
      * to make sure that nothing have been broken in the migration process.
      * They mostly cover search/filters. Some of them might be redundant with the previous ones.
      */
-
     /**
      * Attempt to instantiate a LinkDB whereas the datastore is not writable
-     *
-     * @expectedException              Shaarli\Bookmark\Exception\NotWritableDataStoreException
-     * @expectedExceptionMessageRegExp #Couldn't load data from the data store file "null".*#
      */
     public function testConstructDatastoreNotWriteable()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\NotWritableDataStoreException::class);
+        $this->expectExceptionMessageRegExp('#Couldn\'t load data from the data store file "null".*#');
+
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', 'null/store.db');
         new BookmarkFileService($conf, $this->history, true);
@@ -744,7 +747,7 @@ class BookmarkFileServiceTest extends TestCase
         $link = $this->publicLinkDB->findByUrl('http://mediagoblin.org/');
 
         $this->assertNotEquals(false, $link);
-        $this->assertContains(
+        $this->assertContainsPolyfill(
             'A free software media publishing platform',
             $link->getDescription()
         );
@@ -1061,6 +1064,36 @@ class BookmarkFileServiceTest extends TestCase
         $this->assertEquals($expected, $tags, var_export($tags, true));
     }
 
+    /**
+     * Test filterDay while logged in
+     */
+    public function testFilterDayLoggedIn(): void
+    {
+        $bookmarks = $this->privateLinkDB->filterDay('20121206');
+        $expectedIds = [4, 9, 1, 0];
+
+        static::assertCount(4, $bookmarks);
+        foreach ($bookmarks as $bookmark) {
+            $i = ($i ?? -1) + 1;
+            static::assertSame($expectedIds[$i], $bookmark->getId());
+        }
+    }
+
+    /**
+     * Test filterDay while logged out
+     */
+    public function testFilterDayLoggedOut(): void
+    {
+        $bookmarks = $this->publicLinkDB->filterDay('20121206');
+        $expectedIds = [4, 9, 1];
+
+        static::assertCount(3, $bookmarks);
+        foreach ($bookmarks as $bookmark) {
+            $i = ($i ?? -1) + 1;
+            static::assertSame($expectedIds[$i], $bookmark->getId());
+        }
+    }
+
     /**
      * Allows to test LinkDB's private methods
      *
index d4c71cb94388ca86dede43b8c9054ce96f4e8261..48c7f8247bc02ca32900886e7f7d86aac90027c8 100644 (file)
@@ -3,11 +3,10 @@
 namespace Shaarli\Bookmark;
 
 use Exception;
-use PHPUnit\Framework\TestCase;
 use ReferenceLinkDB;
 use Shaarli\Config\ConfigManager;
-use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkFilterTest.
@@ -36,7 +35,7 @@ class BookmarkFilterTest extends TestCase
     /**
      * Instantiate linkFilter with ReferenceLinkDB data.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', self::$testDatastore);
@@ -189,6 +188,17 @@ class BookmarkFilterTest extends TestCase
         );
     }
 
+    /**
+     * Return bookmarks for a given day
+     */
+    public function testFilterDayRestrictedVisibility(): void
+    {
+        $this->assertEquals(
+            3,
+            count(self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20121206', false, BookmarkFilter::$PUBLIC))
+        );
+    }
+
     /**
      * 404 - day not found
      */
@@ -202,21 +212,23 @@ class BookmarkFilterTest extends TestCase
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayWithChars()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, 'Rainy day, dream away');
     }
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayDigits()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(BookmarkFilter::$FILTER_DAY, '20');
     }
 
@@ -240,11 +252,11 @@ class BookmarkFilterTest extends TestCase
 
     /**
      * No link for this hash
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterUnknownSmallHash()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         self::$linkFilter->filter(BookmarkFilter::$FILTER_HASH, 'Iblaah');
     }
 
index 3906cc7f4e3f542531eaa0b53b3b174c07cfc18a..25704004e8909f9d1d8e3878d1e2043e571f66ce 100644 (file)
@@ -2,9 +2,9 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkInitializerTest
@@ -37,7 +37,7 @@ class BookmarkInitializerTest extends TestCase
     /**
      * Initialize an empty BookmarkFileService
      */
-    public function setUp()
+    public function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
@@ -64,17 +64,26 @@ class BookmarkInitializerTest extends TestCase
 
         $this->initializer->initialize();
 
-        $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count());
+        $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
+
         $bookmark = $this->bookmarkService->get(43);
-        $this->assertEquals(43, $bookmark->getId());
-        $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $bookmark->getDescription()
+        );
         $this->assertTrue($bookmark->isPrivate());
 
         $bookmark = $this->bookmarkService->get(44);
-        $this->assertEquals(44, $bookmark->getId());
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $bookmark->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $bookmark->getDescription()
+        );
+        $this->assertTrue($bookmark->isPrivate());
+
+        $bookmark = $this->bookmarkService->get(45);
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $bookmark->getDescription()
         );
         $this->assertFalse($bookmark->isPrivate());
 
@@ -82,17 +91,26 @@ class BookmarkInitializerTest extends TestCase
 
         // Reload from file
         $this->bookmarkService = new BookmarkFileService($this->conf, $this->history, true);
-        $this->assertEquals($refDB->countLinks() + 2, $this->bookmarkService->count());
+        $this->assertEquals($refDB->countLinks() + 3, $this->bookmarkService->count());
+
         $bookmark = $this->bookmarkService->get(43);
-        $this->assertEquals(43, $bookmark->getId());
-        $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $bookmark->getDescription()
+        );
         $this->assertTrue($bookmark->isPrivate());
 
         $bookmark = $this->bookmarkService->get(44);
-        $this->assertEquals(44, $bookmark->getId());
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $bookmark->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $bookmark->getDescription()
+        );
+        $this->assertTrue($bookmark->isPrivate());
+
+        $bookmark = $this->bookmarkService->get(45);
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $bookmark->getDescription()
         );
         $this->assertFalse($bookmark->isPrivate());
     }
@@ -107,17 +125,25 @@ class BookmarkInitializerTest extends TestCase
 
         $this->initializer->initialize();
 
-        $this->assertEquals(2, $this->bookmarkService->count());
+        $this->assertEquals(3, $this->bookmarkService->count());
         $bookmark = $this->bookmarkService->get(0);
-        $this->assertEquals(0, $bookmark->getId());
-        $this->assertEquals('My secret stuff... - Pastebin.com', $bookmark->getTitle());
+        $this->assertStringStartsWith(
+            'Shaarli will automatically pick up the thumbnail for links to a variety of websites.',
+            $bookmark->getDescription()
+        );
         $this->assertTrue($bookmark->isPrivate());
 
         $bookmark = $this->bookmarkService->get(1);
-        $this->assertEquals(1, $bookmark->getId());
-        $this->assertEquals(
-            'The personal, minimalist, super-fast, database free, bookmarking service',
-            $bookmark->getTitle()
+        $this->assertStringStartsWith(
+            'Adding a shaare without entering a URL creates a text-only "note" post such as this one.',
+            $bookmark->getDescription()
+        );
+        $this->assertTrue($bookmark->isPrivate());
+
+        $bookmark = $this->bookmarkService->get(2);
+        $this->assertStringStartsWith(
+            'Welcome to Shaarli!',
+            $bookmark->getDescription()
         );
         $this->assertFalse($bookmark->isPrivate());
     }
index 4b6a3c07c6207e6b41f6ec65b75fb4c79f333de6..afec24403e75bb0c34255e9dff54db987ecdc3e4 100644 (file)
@@ -2,8 +2,8 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Exception\InvalidBookmarkException;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkTest
@@ -150,7 +150,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- ID: '. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- ID: '. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -169,7 +169,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- ID: str'. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- ID: str'. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -188,7 +188,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- ShortUrl: '. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- ShortUrl: '. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -207,7 +207,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- Created: '. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- Created: '. PHP_EOL, $exception->getMessage());
     }
 
     /**
@@ -226,7 +226,7 @@ class BookmarkTest extends TestCase
             $exception = $e;
         }
         $this->assertNotNull($exception);
-        $this->assertContains('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage());
+        $this->assertContainsPolyfill('- Created: Not a DateTime object'. PHP_EOL, $exception->getMessage());
     }
 
     /**
index cc7819bcd767825318d0b7ce7dd5e8f69883ecfe..29941c8cd0ed32307faa0eea5bde9b99b3d77967 100644 (file)
@@ -2,7 +2,7 @@
 
 namespace Shaarli\Bookmark;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 require_once 'tests/utils/CurlUtils.php';
 
@@ -42,6 +42,19 @@ class LinkUtilsTest extends TestCase
         $this->assertEquals(strtolower($charset), header_extract_charset($headers));
     }
 
+    /**
+     * Test headers_extract_charset() when the charset is found with odd quotes.
+     */
+    public function testHeadersExtractExistentCharsetWithQuotes()
+    {
+        $charset = 'x-MacCroatian';
+        $headers = 'text/html; charset="' . $charset . '"otherstuff="test"';
+        $this->assertEquals(strtolower($charset), header_extract_charset($headers));
+
+        $headers = 'text/html; charset=\'' . $charset . '\'otherstuff="test"';
+        $this->assertEquals(strtolower($charset), header_extract_charset($headers));
+    }
+
     /**
      * Test headers_extract_charset() when the charset is not found.
      */
@@ -526,13 +539,13 @@ class LinkUtilsTest extends TestCase
             カタカナ #カタカナ」カタカナ\n';
         $autolinkedDescription = hashtag_autolink($rawDescription, $index);
 
-        $this->assertContains($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
-        $this->assertNotContains(' #hashtag', $autolinkedDescription);
-        $this->assertNotContains('>#nothashtag', $autolinkedDescription);
-        $this->assertContains($this->getHashtagLink('ашок', $index), $autolinkedDescription);
-        $this->assertContains($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
-        $this->assertContains($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
-        $this->assertNotContains($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('hashtag', $index), $autolinkedDescription);
+        $this->assertNotContainsPolyfill(' #hashtag', $autolinkedDescription);
+        $this->assertNotContainsPolyfill('>#nothashtag', $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('ашок', $index), $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('カタカナ', $index), $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('hashtag_hashtag', $index), $autolinkedDescription);
+        $this->assertNotContainsPolyfill($this->getHashtagLink('hashtag-nothashtag', $index), $autolinkedDescription);
     }
 
     /**
@@ -543,9 +556,9 @@ class LinkUtilsTest extends TestCase
         $rawDescription = 'blabla #hashtag x#nothashtag';
         $autolinkedDescription = hashtag_autolink($rawDescription);
 
-        $this->assertContains($this->getHashtagLink('hashtag'), $autolinkedDescription);
-        $this->assertNotContains(' #hashtag', $autolinkedDescription);
-        $this->assertNotContains('>#nothashtag', $autolinkedDescription);
+        $this->assertContainsPolyfill($this->getHashtagLink('hashtag'), $autolinkedDescription);
+        $this->assertNotContainsPolyfill(' #hashtag', $autolinkedDescription);
+        $this->assertNotContainsPolyfill('>#nothashtag', $autolinkedDescription);
     }
 
     /**
index d4ddedd50a6f06d26d05a12121be7c29c6392a64..2d675c9a006d9ab24f1e4e522df8f5a7e7de476e 100644 (file)
@@ -18,6 +18,7 @@ require_once 'application/bookmark/LinkUtils.php';
 require_once 'application/Utils.php';
 require_once 'application/http/UrlUtils.php';
 require_once 'application/http/HttpUtils.php';
+require_once 'tests/TestCase.php';
 require_once 'tests/container/ShaarliTestContainer.php';
 require_once 'tests/front/controller/visitor/FrontControllerMockHelper.php';
 require_once 'tests/front/controller/admin/FrontAdminControllerMockHelper.php';
index 33160eb0d88dd7d37bd69aa2c903a84515a7baf8..c0ba5b8f07c1c0513ae26050408b3c76f326b9ae 100644 (file)
@@ -4,14 +4,14 @@ namespace Shaarli\Config;
 /**
  * Class ConfigJsonTest
  */
-class ConfigJsonTest extends \PHPUnit\Framework\TestCase
+class ConfigJsonTest extends \Shaarli\TestCase
 {
     /**
      * @var ConfigJson
      */
     protected $configIO;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->configIO = new ConfigJson();
     }
@@ -38,12 +38,12 @@ class ConfigJsonTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Read a non existent config file -> empty array.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp  /An error occurred while parsing JSON configuration file \([\w\/\.]+\): error code #4/
      */
     public function testReadInvalidJson()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/An error occurred while parsing JSON configuration file \\([\\w\\/\\.]+\\): error code #4/');
+
         $this->configIO->read('tests/utils/config/configInvalid.json.php');
     }
 
@@ -110,22 +110,11 @@ class ConfigJsonTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Write to invalid path.
-     *
-     * @expectedException \Shaarli\Exceptions\IOException
-     */
-    public function testWriteInvalidArray()
-    {
-        $conf = array('conf' => 'value');
-        @$this->configIO->write(array(), $conf);
-    }
-
-    /**
-     * Write to invalid path.
-     *
-     * @expectedException \Shaarli\Exceptions\IOException
      */
     public function testWriteInvalidBlank()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+
         $conf = array('conf' => 'value');
         @$this->configIO->write('', $conf);
     }
index 33830bc94bcc3584380b1a18259e4cf9ec101980..65d8ba2c64f70aa58893a9a31f0ae0d08b42c2d5 100644 (file)
@@ -7,14 +7,14 @@ namespace Shaarli\Config;
  * Note: it only test the manager with ConfigJson,
  *  ConfigPhp is only a workaround to handle the transition to JSON type.
  */
-class ConfigManagerTest extends \PHPUnit\Framework\TestCase
+class ConfigManagerTest extends \Shaarli\TestCase
 {
     /**
      * @var ConfigManager
      */
     protected $conf;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager('tests/utils/config/configJson');
     }
@@ -95,44 +95,44 @@ class ConfigManagerTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Set with an empty key.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
      */
     public function testSetEmptyKey()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
+
         $this->conf->set('', 'stuff');
     }
 
     /**
      * Set with an array key.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
      */
     public function testSetArrayKey()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
+
         $this->conf->set(array('foo' => 'bar'), 'stuff');
     }
 
     /**
      * Remove with an empty key.
-     *
-     * @expectedException \Exception
-     * @expectedExceptionMessageRegExp #^Invalid setting key parameter. String expected, got.*#
      */
     public function testRmoveEmptyKey()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('#^Invalid setting key parameter. String expected, got.*#');
+
         $this->conf->remove('');
     }
 
     /**
      * Try to write the config without mandatory parameter (e.g. 'login').
-     *
-     * @expectedException Shaarli\Config\Exception\MissingFieldConfigException
      */
     public function testWriteMissingParameter()
     {
+        $this->expectException(\Shaarli\Config\Exception\MissingFieldConfigException::class);
+
         $this->conf->setConfigFile('tests/utils/config/configTmp');
         $this->assertFalse(file_exists($this->conf->getConfigFileExt()));
         $this->conf->reload();
index fb91b51ba6007e9c1452dea17fa6681076ff1bc1..7bf9fe64933925d23c4f96362894c512ea918997 100644 (file)
@@ -8,14 +8,14 @@ namespace Shaarli\Config;
  * which are kept between tests.
  * @runTestsInSeparateProcesses
  */
-class ConfigPhpTest extends \PHPUnit\Framework\TestCase
+class ConfigPhpTest extends \Shaarli\TestCase
 {
     /**
      * @var ConfigPhp
      */
     protected $configIO;
 
-    public function setUp()
+    protected function setUp(): void
     {
         $this->configIO = new ConfigPhp();
     }
index b2cc00455284b8fe339caae0bd02b31f8f1ec696..fa72d8c4ae40438ccdac5af72c3734cd192fb0b5 100644 (file)
@@ -9,7 +9,7 @@ require_once 'application/config/ConfigPlugin.php';
 /**
  * Unitary tests for Shaarli config related functions
  */
-class ConfigPluginTest extends \PHPUnit\Framework\TestCase
+class ConfigPluginTest extends \Shaarli\TestCase
 {
     /**
      * Test save_plugin_config with valid data.
@@ -46,11 +46,11 @@ class ConfigPluginTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test save_plugin_config with invalid data.
-     *
-     * @expectedException Shaarli\Config\Exception\PluginConfigOrderException
      */
     public function testSavePluginConfigInvalid()
     {
+        $this->expectException(\Shaarli\Config\Exception\PluginConfigOrderException::class);
+
         $data = array(
             'plugin2' => 0,
             'plugin3' => 0,
index c08010ae915a778e161a424d0ead26a097b20d5e..5d52daefd5f7cf0e8d62559ee19cd8853c9e8e6a 100644 (file)
@@ -4,12 +4,12 @@ declare(strict_types=1);
 
 namespace Shaarli\Container;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Feed\FeedBuilder;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\Front\Controller\Visitor\ErrorController;
+use Shaarli\Front\Controller\Visitor\ErrorNotFoundController;
 use Shaarli\History;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
@@ -19,6 +19,7 @@ use Shaarli\Render\PageCacheManager;
 use Shaarli\Security\CookieManager;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Shaarli\Updater\Updater;
 use Slim\Http\Environment;
@@ -75,6 +76,7 @@ class ContainerBuilderTest extends TestCase
         static::assertInstanceOf(PageBuilder::class, $container->pageBuilder);
         static::assertInstanceOf(PageCacheManager::class, $container->pageCacheManager);
         static::assertInstanceOf(ErrorController::class, $container->phpErrorHandler);
+        static::assertInstanceOf(ErrorNotFoundController::class, $container->notFoundHandler);
         static::assertInstanceOf(PluginManager::class, $container->pluginManager);
         static::assertInstanceOf(SessionManager::class, $container->sessionManager);
         static::assertInstanceOf(Thumbnailer::class, $container->thumbnailer);
index 2e7164321d85e7ca0e487fa69a8a6c1f64faeb82..904db9dc2251a4f23da5ecbf57df59c1b85e5d72 100644 (file)
@@ -7,7 +7,7 @@ namespace Shaarli\Feed;
 /**
  * Unitary tests for cached pages
  */
-class CachedPageTest extends \PHPUnit\Framework\TestCase
+class CachedPageTest extends \Shaarli\TestCase
 {
     // test cache directory
     protected static $testCacheDir = 'sandbox/pagecache';
@@ -17,7 +17,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase
     /**
      * Create the cache directory if needed
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         if (!is_dir(self::$testCacheDir)) {
             mkdir(self::$testCacheDir);
@@ -28,7 +28,7 @@ class CachedPageTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset the page cache
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$filename)) {
             unlink(self::$filename);
index fe37d5f23a08068ddb2e8e91f77c872225173deb..c29e8ef3b01753b42f3cb37544cb49c165439a67 100644 (file)
@@ -10,13 +10,14 @@ use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 /**
  * FeedBuilderTest class.
  *
  * Unit tests for FeedBuilder.
  */
-class FeedBuilderTest extends \PHPUnit\Framework\TestCase
+class FeedBuilderTest extends TestCase
 {
     /**
      * @var string locale Basque (Spain).
@@ -44,7 +45,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
     /**
      * Called before every test method.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         $conf = new ConfigManager('tests/utils/config/configJson');
         $conf->set('resource.datastore', self::$testDatastore);
@@ -60,7 +61,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
             'SERVER_NAME' => 'host.tld',
             'SERVER_PORT' => '80',
             'SCRIPT_NAME' => '/index.php',
-            'REQUEST_URI' => '/index.php?do=feed',
+            'REQUEST_URI' => '/feed/atom',
         );
     }
 
@@ -81,7 +82,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(self::$RSS_LANGUAGE, $data['language']);
         $this->assertRegExp('/Wed, 03 Aug 2016 09:30:33 \+\d{4}/', $data['last_update']);
         $this->assertEquals(true, $data['show_dates']);
-        $this->assertEquals('http://host.tld/index.php?do=feed', $data['self_link']);
+        $this->assertEquals('http://host.tld/feed/atom', $data['self_link']);
         $this->assertEquals('http://host.tld/', $data['index_url']);
         $this->assertFalse($data['usepermalinks']);
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
@@ -96,9 +97,9 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $pub = DateTime::createFromFormat(DateTime::RSS, $link['pub_iso_date']);
         $up = DateTime::createFromFormat(DateTime::ATOM, $link['up_iso_date']);
         $this->assertEquals($pub, $up);
-        $this->assertContains('Stallman has a beard', $link['description']);
-        $this->assertContains('Permalink', $link['description']);
-        $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
+        $this->assertContainsPolyfill('Stallman has a beard', $link['description']);
+        $this->assertContainsPolyfill('Permalink', $link['description']);
+        $this->assertContainsPolyfill('http://host.tld/shaare/WDWyig', $link['description']);
         $this->assertEquals(1, count($link['taglist']));
         $this->assertEquals('sTuff', $link['taglist'][0]);
 
@@ -200,16 +201,16 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld/shaare/WDWyig', $link['url']);
-        $this->assertContains('Direct link', $link['description']);
-        $this->assertContains('http://host.tld/shaare/WDWyig', $link['description']);
+        $this->assertContainsPolyfill('Direct link', $link['description']);
+        $this->assertContainsPolyfill('http://host.tld/shaare/WDWyig', $link['description']);
         // Second link is a direct link
         $link = $data['links'][array_keys($data['links'])[1]];
         $this->assertEquals(8, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(Bookmark::LINK_DATE_FORMAT, '20150310_114633'), $link['created']);
         $this->assertEquals('http://host.tld/shaare/RttfEw', $link['guid']);
         $this->assertEquals('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['url']);
-        $this->assertContains('Direct link', $link['description']);
-        $this->assertContains('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']);
+        $this->assertContainsPolyfill('Direct link', $link['description']);
+        $this->assertContainsPolyfill('https://static.fsf.org/nosvn/faif-2.0.pdf', $link['description']);
     }
 
     /**
@@ -253,7 +254,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
             'SERVER_NAME' => 'host.tld',
             'SERVER_PORT' => '8080',
             'SCRIPT_NAME' => '/~user/shaarli/index.php',
-            'REQUEST_URI' => '/~user/shaarli/index.php?do=feed',
+            'REQUEST_URI' => '/~user/shaarli/feed/atom',
         );
         $feedBuilder = new FeedBuilder(
             self::$bookmarkService,
@@ -265,7 +266,7 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $data = $feedBuilder->buildData(FeedBuilder::$FEED_ATOM, null);
 
         $this->assertEquals(
-            'http://host.tld:8080/~user/shaarli/index.php?do=feed',
+            'http://host.tld:8080/~user/shaarli/feed/atom',
             $data['self_link']
         );
 
@@ -273,6 +274,6 @@ class FeedBuilderTest extends \PHPUnit\Framework\TestCase
         $link = $data['links'][array_keys($data['links'])[0]];
         $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld:8080/~user/shaarli/shaare/WDWyig', $link['url']);
-        $this->assertContains('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
+        $this->assertContainsPolyfill('http://host.tld:8080/~user/shaarli/./add-tag/hashtag', $link['description']);
     }
 }
index cf48b00b63ce2c397a89cf836d1d9b04e812e9b9..9534436e3f7e7150c19a50022be476a36754f6b2 100644 (file)
@@ -3,9 +3,9 @@
 namespace Shaarli\Formatter;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkDefaultFormatterTest
@@ -25,7 +25,7 @@ class BookmarkDefaultFormatterTest extends TestCase
     /**
      * Initialize formatter instance.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
diff --git a/tests/formatter/BookmarkMarkdownExtraFormatterTest.php b/tests/formatter/BookmarkMarkdownExtraFormatterTest.php
new file mode 100644 (file)
index 0000000..d4941ef
--- /dev/null
@@ -0,0 +1,162 @@
+<?php
+
+namespace Shaarli\Formatter;
+
+use DateTime;
+use PHPUnit\Framework\TestCase;
+use Shaarli\Bookmark\Bookmark;
+use Shaarli\Config\ConfigManager;
+
+/**
+ * Class BookmarkMarkdownExtraFormatterTest
+ * @package Shaarli\Formatter
+ */
+class BookmarkMarkdownExtraFormatterTest extends TestCase
+{
+    /** @var string Path of test config file */
+    protected static $testConf = 'sandbox/config';
+
+    /** @var BookmarkFormatter */
+    protected $formatter;
+
+    /** @var ConfigManager instance */
+    protected $conf;
+
+    /**
+     * Initialize formatter instance.
+     */
+    public function setUp(): void
+    {
+        copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
+        $this->conf = new ConfigManager(self::$testConf);
+        $this->formatter = new BookmarkMarkdownExtraFormatter($this->conf, true);
+    }
+
+    /**
+     * Test formatting a bookmark with all its attribute filled.
+     */
+    public function testFormatExtra(): void
+    {
+        $bookmark = new Bookmark();
+        $bookmark->setId($id = 11);
+        $bookmark->setShortUrl($short = 'abcdef');
+        $bookmark->setUrl('https://sub.domain.tld?query=here&for=real#hash');
+        $bookmark->setTitle($title = 'This is a <strong>bookmark</strong>');
+        $bookmark->setDescription('<h2>Content</h2><p>`Here is some content</p>');
+        $bookmark->setTags($tags = ['tag1', 'bookmark', 'other', '<script>alert("xss");</script>']);
+        $bookmark->setThumbnail('http://domain2.tdl2/?type=img&name=file.png');
+        $bookmark->setSticky(true);
+        $bookmark->setCreated($created = DateTime::createFromFormat('Ymd_His', '20190521_190412'));
+        $bookmark->setUpdated($updated = DateTime::createFromFormat('Ymd_His', '20190521_191213'));
+        $bookmark->setPrivate(true);
+
+        $link = $this->formatter->format($bookmark);
+        $this->assertEquals($id, $link['id']);
+        $this->assertEquals($short, $link['shorturl']);
+        $this->assertEquals('https://sub.domain.tld?query=here&amp;for=real#hash', $link['url']);
+        $this->assertEquals(
+            'https://sub.domain.tld?query=here&amp;for=real#hash',
+            $link['real_url']
+        );
+        $this->assertEquals('This is a &lt;strong&gt;bookmark&lt;/strong&gt;', $link['title']);
+        $this->assertEquals(
+            '<div class="markdown"><p>'.
+                '&lt;h2&gt;Content&lt;/h2&gt;&lt;p&gt;`Here is some content&lt;/p&gt;'.
+            '</p></div>',
+            $link['description']
+        );
+        $tags[3] = '&lt;script&gt;alert(&quot;xss&quot;);&lt;/script&gt;';
+        $this->assertEquals($tags, $link['taglist']);
+        $this->assertEquals(implode(' ', $tags), $link['tags']);
+        $this->assertEquals(
+            'http://domain2.tdl2/?type=img&amp;name=file.png',
+            $link['thumbnail']
+        );
+        $this->assertEquals($created, $link['created']);
+        $this->assertEquals($created->getTimestamp(), $link['timestamp']);
+        $this->assertEquals($updated, $link['updated']);
+        $this->assertEquals($updated->getTimestamp(), $link['updated_timestamp']);
+        $this->assertTrue($link['private']);
+        $this->assertTrue($link['sticky']);
+        $this->assertEquals('private', $link['class']);
+    }
+
+    /**
+     * Test formatting a bookmark with all its attribute filled.
+     */
+    public function testFormatExtraMinimal(): void
+    {
+        $bookmark = new Bookmark();
+
+        $link = $this->formatter->format($bookmark);
+        $this->assertEmpty($link['id']);
+        $this->assertEmpty($link['shorturl']);
+        $this->assertEmpty($link['url']);
+        $this->assertEmpty($link['real_url']);
+        $this->assertEmpty($link['title']);
+        $this->assertEmpty($link['description']);
+        $this->assertEmpty($link['taglist']);
+        $this->assertEmpty($link['tags']);
+        $this->assertEmpty($link['thumbnail']);
+        $this->assertEmpty($link['created']);
+        $this->assertEmpty($link['timestamp']);
+        $this->assertEmpty($link['updated']);
+        $this->assertEmpty($link['updated_timestamp']);
+        $this->assertFalse($link['private']);
+        $this->assertFalse($link['sticky']);
+        $this->assertEmpty($link['class']);
+    }
+
+    /**
+     * Make sure that the description is properly formatted by the default formatter.
+     */
+    public function testFormatExtrraDescription(): void
+    {
+        $description = 'This a <strong>description</strong>'. PHP_EOL;
+        $description .= 'text https://sub.domain.tld?query=here&for=real#hash more text'. PHP_EOL;
+        $description .= 'Also, there is an #hashtag added'. PHP_EOL;
+        $description .= '    A  N  D KEEP     SPACES    !   '. PHP_EOL;
+        $description .= '# Header {.class}'. PHP_EOL;
+
+        $bookmark = new Bookmark();
+        $bookmark->setDescription($description);
+        $link = $this->formatter->format($bookmark);
+
+        $description = '<div class="markdown"><p>';
+        $description .= 'This a &lt;strong&gt;description&lt;/strong&gt;<br />'. PHP_EOL;
+        $url = 'https://sub.domain.tld?query=here&amp;for=real#hash';
+        $description .= 'text <a href="'. $url .'">'. $url .'</a> more text<br />'. PHP_EOL;
+        $description .= 'Also, there is an <a href="./add-tag/hashtag">#hashtag</a> added<br />'. PHP_EOL;
+        $description .= 'A  N  D KEEP     SPACES    !   </p>' . PHP_EOL;
+        $description .= '<h1 class="class">Header</h1>';
+        $description .= '</div>';
+
+        $this->assertEquals($description, $link['description']);
+    }
+
+    /**
+     * Test formatting URL with an index_url set
+     * It should prepend relative links.
+     */
+    public function testFormatExtraNoteWithIndexUrl(): void
+    {
+        $bookmark = new Bookmark();
+        $bookmark->setUrl($short = '?abcdef');
+        $description = 'Text #hashtag more text';
+        $bookmark->setDescription($description);
+
+        $this->formatter->addContextData('index_url', $root = 'https://domain.tld/hithere/');
+
+        $description = '<div class="markdown"><p>';
+        $description .= 'Text <a href="'. $root .'./add-tag/hashtag">#hashtag</a> more text';
+        $description .= '</p></div>';
+
+        $link = $this->formatter->format($bookmark);
+        $this->assertEquals($root . $short, $link['url']);
+        $this->assertEquals($root . $short, $link['real_url']);
+        $this->assertEquals(
+            $description,
+            $link['description']
+        );
+    }
+}
index 3e72d1eea340988b4b69c4f94e9cfdc2907d2cbf..ab6b40809ab4563337142b03ded08261a893b065 100644 (file)
@@ -3,9 +3,9 @@
 namespace Shaarli\Formatter;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkMarkdownFormatterTest
@@ -25,7 +25,7 @@ class BookmarkMarkdownFormatterTest extends TestCase
     /**
      * Initialize formatter instance.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
index 4491b03586ad7fddb1da215df67924d251435b3a..c76bb7b9f7138e81b76057d8ac535c4219fec539 100644 (file)
@@ -3,9 +3,9 @@
 namespace Shaarli\Formatter;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class BookmarkRawFormatterTest
@@ -25,7 +25,7 @@ class BookmarkRawFormatterTest extends TestCase
     /**
      * Initialize formatter instance.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
index 5adf3ffd8dd2acfe20eb47fcf5ab58ed40f7c9ce..ae476cb5057df02ca9babf3c9fe83daec05f0e85 100644 (file)
@@ -2,8 +2,8 @@
 
 namespace Shaarli\Formatter;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
+use Shaarli\TestCase;
 
 /**
  * Class FormatterFactoryTest
@@ -24,7 +24,7 @@ class FormatterFactoryTest extends TestCase
     /**
      * Initialize FormatterFactory instance
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$testConf .'.json.php');
         $this->conf = new ConfigManager(self::$testConf);
index 7451330bcde5e037eaaa5043d4e4a0b90410a65c..44025f1137ba3ec213f01109b70ac10a8dc55e0f 100644 (file)
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliContainer;
 use Shaarli\Security\LoginManager;
+use Shaarli\TestCase;
 use Shaarli\Updater\Updater;
 use Slim\Http\Request;
 use Slim\Http\Response;
index 05aa34a9d5acfb30f28f8b3794730b989a538a7f..655c5bba635ff2ec8ce3df3ba5a9bafacbf17051 100644 (file)
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliContainer;
 use Shaarli\Front\Exception\LoginBannedException;
@@ -12,6 +11,7 @@ use Shaarli\Front\Exception\UnauthorizedException;
 use Shaarli\Render\PageBuilder;
 use Shaarli\Render\PageCacheManager;
 use Shaarli\Security\LoginManager;
+use Shaarli\TestCase;
 use Shaarli\Updater\Updater;
 use Slim\Http\Request;
 use Slim\Http\Response;
index 612f20f12588a62c03060a27a0aa7da00298b8b2..d82db0a7c3e4692b4fb9bd9be81bdde4def86a11 100644 (file)
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -51,7 +51,7 @@ class ConfigureControllerTest extends TestCase
         static::assertSame('general.title', $assignedVariables['title']);
         static::assertSame('resource.theme', $assignedVariables['theme']);
         static::assertEmpty($assignedVariables['theme_available']);
-        static::assertSame(['default', 'markdown'], $assignedVariables['formatter_available']);
+        static::assertSame(['default', 'markdown', 'markdownExtra'], $assignedVariables['formatter_available']);
         static::assertNotEmpty($assignedVariables['continents']);
         static::assertNotEmpty($assignedVariables['cities']);
         static::assertSame('general.retrieve_description', $assignedVariables['retrieve_description']);
index 50d9e378752f890024c8ee59e89ebd1f3120be4a..0e6f2762ed6fe25ac523ee1371ab5ba5e5387e24 100644 (file)
@@ -4,12 +4,12 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Formatter\BookmarkFormatter;
 use Shaarli\Formatter\BookmarkRawFormatter;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -84,7 +84,7 @@ class ExportControllerTest extends TestCase
                     static::assertInstanceOf(BookmarkRawFormatter::class, $formatter);
                     static::assertSame($parameters['selection'], $selection);
                     static::assertTrue($prependNoteUrl);
-                    static::assertSame('http://shaarli', $indexUrl);
+                    static::assertSame('http://shaarli/subfolder/', $indexUrl);
 
                     return $bookmarks;
                 }
index eb31fad08bfe33dd783ac9186d3426ed615acf49..c266caa59b13bacd3092b4e4be7516c71145fa51 100644 (file)
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UploadedFileInterface;
 use Shaarli\Netscape\NetscapeBookmarkUtils;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 use Slim\Http\UploadedFile;
index 45e84dc035b65d89984377bb507bdcbc5d7d27d4..94e53019a967d6a5a028850c534bb857843908e0 100644 (file)
@@ -4,10 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\CookieManager;
-use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 7d5b752a934201fb29bce4038153414882a54e68..0f27ec2fd3d66f66090302cad3abf6df74ac671c 100644 (file)
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 5a61579176d8ef2e522311450360f4bf3e44dbf5..096d077435886686484b627a035ef769ea5d2d65 100644 (file)
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Formatter\BookmarkFormatter;
@@ -14,6 +13,7 @@ use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index dee622bba829104be8ade4486dce594b1e4eb39a..ba774e2119137248bd5d23797137bbc006327f0f 100644 (file)
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Formatter\BookmarkFormatter;
@@ -13,6 +12,7 @@ use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 777583d586c92986f7fd31649371c983b11ee1d2..2eb952514b8d1b0cd622bb7c3cd96253081fe812 100644 (file)
@@ -4,12 +4,12 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -96,12 +96,14 @@ class DisplayCreateFormTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_editlink'], ['render_includes'])
             ->willReturnCallback(function (string $hook, array $data) use ($remoteTitle, $remoteDesc): array {
-                static::assertSame('render_editlink', $hook);
-                static::assertSame($remoteTitle, $data['link']['title']);
-                static::assertSame($remoteDesc, $data['link']['description']);
+                if ('render_editlink' === $hook) {
+                    static::assertSame($remoteTitle, $data['link']['title']);
+                    static::assertSame($remoteDesc, $data['link']['description']);
+                }
 
                 return $data;
             })
index 1a1cdcf312a22a64f394195b91fd0cd651501c48..2dc3f41c65b303bbb658ee6cf57bfea94ed4f607 100644 (file)
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 1607b47523ec2c6659d0c359e5516c6599c9131c..50ce7df14fabe73c7005125d9970ccb43091284e 100644 (file)
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
 use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index dabcd60d9d28f373bd552300204488d2643c958b..f7a68226148e4b9434649b8fb409956745322416 100644 (file)
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin\ManageShaareControllerTest;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Controller\Admin\FrontAdminControllerMockHelper;
@@ -12,6 +11,7 @@ use Shaarli\Front\Controller\Admin\ManageShaareController;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Http\HttpAccess;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -43,7 +43,7 @@ class SaveBookmarkTest extends TestCase
             'lf_description' => 'Provided description.',
             'lf_tags' => 'abc def',
             'lf_private' => '1',
-            'returnurl' => 'http://shaarli.tld/subfolder/admin/add-shaare'
+            'returnurl' => 'http://shaarli/subfolder/admin/add-shaare'
         ];
 
         $request = $this->createMock(Request::class);
@@ -88,17 +88,18 @@ class SaveBookmarkTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['save_link'])
             ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
-                static::assertSame('save_link', $hook);
-
-                static::assertSame($id, $data['id']);
-                static::assertSame($parameters['lf_url'], $data['url']);
-                static::assertSame($parameters['lf_title'], $data['title']);
-                static::assertSame($parameters['lf_description'], $data['description']);
-                static::assertSame($parameters['lf_tags'], $data['tags']);
-                static::assertTrue($data['private']);
+                if ('save_link' === $hook) {
+                    static::assertSame($id, $data['id']);
+                    static::assertSame($parameters['lf_url'], $data['url']);
+                    static::assertSame($parameters['lf_title'], $data['title']);
+                    static::assertSame($parameters['lf_description'], $data['description']);
+                    static::assertSame($parameters['lf_tags'], $data['tags']);
+                    static::assertTrue($data['private']);
+                }
 
                 return $data;
             })
@@ -124,7 +125,7 @@ class SaveBookmarkTest extends TestCase
             'lf_description' => 'Provided description.',
             'lf_tags' => 'abc def',
             'lf_private' => '1',
-            'returnurl' => 'http://shaarli.tld/subfolder/?page=2'
+            'returnurl' => 'http://shaarli/subfolder/?page=2'
         ];
 
         $request = $this->createMock(Request::class);
@@ -174,17 +175,18 @@ class SaveBookmarkTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['save_link'])
             ->willReturnCallback(function (string $hook, array $data) use ($parameters, $id): array {
-                static::assertSame('save_link', $hook);
-
-                static::assertSame($id, $data['id']);
-                static::assertSame($parameters['lf_url'], $data['url']);
-                static::assertSame($parameters['lf_title'], $data['title']);
-                static::assertSame($parameters['lf_description'], $data['description']);
-                static::assertSame($parameters['lf_tags'], $data['tags']);
-                static::assertTrue($data['private']);
+                if ('save_link' === $hook) {
+                    static::assertSame($id, $data['id']);
+                    static::assertSame($parameters['lf_url'], $data['url']);
+                    static::assertSame($parameters['lf_title'], $data['title']);
+                    static::assertSame($parameters['lf_description'], $data['description']);
+                    static::assertSame($parameters['lf_tags'], $data['tags']);
+                    static::assertTrue($data['private']);
+                }
 
                 return $data;
             })
@@ -238,6 +240,30 @@ class SaveBookmarkTest extends TestCase
         static::assertSame(302, $result->getStatusCode());
     }
 
+    /**
+     * Test save a bookmark - with ID #0
+     */
+    public function testSaveBookmarkWithIdZero(): void
+    {
+        $parameters = ['lf_id' => '0'];
+
+        $request = $this->createMock(Request::class);
+        $request
+            ->method('getParam')
+            ->willReturnCallback(function (string $key) use ($parameters): ?string {
+                return $parameters[$key] ?? null;
+            })
+        ;
+        $response = new Response();
+
+        $this->container->bookmarkService->expects(static::once())->method('exists')->with(0)->willReturn(true);
+        $this->container->bookmarkService->expects(static::once())->method('get')->with(0)->willReturn(new Bookmark());
+
+        $result = $this->controller->save($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+    }
+
     /**
      * Change the password with a wrong existing password
      */
index 09ba0b4b7a4d986df45adb866f7db0380edcd39d..8a0ff7a96ead9956bd9429a746a2be64d47b2fa7 100644 (file)
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFilter;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 9a01089e2ddecd3747e54a968b846e35c091bdaa..58f47b4929ad5748fc77be66e2dfc82ad2728201 100644 (file)
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\OpenShaarliPasswordException;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 5b59285c9916486bdb5719f54c69fcfb94332127..974d614d4c0642cf894bdd29c16c98f8c8f233f0 100644 (file)
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Plugin\PluginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -32,7 +32,7 @@ class PluginsControllerTest extends TestCase
         array_map(function (string $plugin) use ($path) { touch($path . '/' . $plugin); }, static::PLUGIN_NAMES);
     }
 
-    public function tearDown()
+    public function tearDown(): void
     {
         $path = __DIR__ . '/folder';
         array_map(function (string $plugin) use ($path) { unlink($path . '/' . $plugin); }, static::PLUGIN_NAMES);
@@ -125,6 +125,7 @@ class PluginsControllerTest extends TestCase
             'parameters_form' => true,
             'parameter1' => 'blip',
             'parameter2' => 'blop',
+            'token' => 'this parameter should not be saved'
         ];
 
         $request = $this->createMock(Request::class);
@@ -143,7 +144,7 @@ class PluginsControllerTest extends TestCase
             ->with('save_plugin_parameters', $parameters)
         ;
         $this->container->conf
-            ->expects(static::atLeastOnce())
+            ->expects(static::exactly(2))
             ->method('set')
             ->withConsecutive(['plugins.parameter1', 'blip'], ['plugins.parameter2', 'blop'])
         ;
index d306c6e9863dcedb71625c596b01b63d141f3860..712a625b2cda3594c3d899342595b048c7485f7e 100644 (file)
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\LoginManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -31,7 +31,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'private'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager->method('isLoggedIn')->willReturn(true);
         $this->container->sessionManager
@@ -57,7 +57,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'private'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager->method('isLoggedIn')->willReturn(true);
         $this->container->sessionManager
@@ -121,7 +121,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'test'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager->method('isLoggedIn')->willReturn(true);
         $this->container->sessionManager
@@ -151,7 +151,7 @@ class SessionFilterControllerTest extends TestCase
     {
         $arg = ['visibility' => 'test'];
 
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $this->container->loginManager = $this->createMock(LoginManager::class);
         $this->container->loginManager->method('isLoggedIn')->willReturn(false);
index fff427cb413a32f73a0ad50c2a5cac3ff4c025c6..486d5d2d416672ca52e5aa458efeadb68b023959 100644 (file)
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 
 /**
index 0c0c8a83b0fbcb7ee427c63badb23552012b2e6f..f4a8acffbdc822790bc6f5a30de0934022719d55 100644 (file)
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
index 04b0c0fa22bbe6cb9ab49fb2992567abbadba936..d2f0907f5715f86b8901b7e8d9de38cb30e739bd 100644 (file)
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index fc756f0ffcf75889285014460ccee28722c030bc..e82f8b143c050b67e790e41ab64d153b17a6acde 100644 (file)
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Admin;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
-class ToolsControllerTestControllerTest extends TestCase
+class ToolsControllerTest extends TestCase
 {
     use FrontAdminControllerMockHelper;
 
@@ -41,7 +41,7 @@ class ToolsControllerTestControllerTest extends TestCase
 
         static::assertSame(200, $result->getStatusCode());
         static::assertSame('tools', (string) $result->getBody());
-        static::assertSame('https://shaarli', $assignedVariables['pageabsaddr']);
+        static::assertSame('https://shaarli/', $assignedVariables['pageabsaddr']);
         static::assertTrue($assignedVariables['sslenabled']);
     }
 
@@ -63,7 +63,7 @@ class ToolsControllerTestControllerTest extends TestCase
 
         static::assertSame(200, $result->getStatusCode());
         static::assertSame('tools', (string) $result->getBody());
-        static::assertSame('http://shaarli', $assignedVariables['pageabsaddr']);
+        static::assertSame('http://shaarli/', $assignedVariables['pageabsaddr']);
         static::assertFalse($assignedVariables['sslenabled']);
     }
 }
index 5daaa2c41a6255b85e66ba4dccf3a53cc4a4db8d..0c95df97554a0a80129ea0ef64a8b17bcbbdfe41 100644 (file)
@@ -4,11 +4,11 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\Exception\BookmarkNotFoundException;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Security\LoginManager;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
index b802c62c53da3c4a5129dce75168dec552df22d8..fc78bc13dc5020411198d2f710ccda1dc79fa016 100644 (file)
@@ -4,9 +4,9 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Feed\CachedPage;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -78,19 +78,20 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_daily'])
             ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array {
-                static::assertSame('render_daily', $hook);
+                if ('render_daily' === $hook) {
+                    static::assertArrayHasKey('linksToDisplay', $data);
+                    static::assertCount(3, $data['linksToDisplay']);
+                    static::assertSame(1, $data['linksToDisplay'][0]['id']);
+                    static::assertSame($currentDay->getTimestamp(), $data['day']);
+                    static::assertSame('20200510', $data['previousday']);
+                    static::assertSame('20200516', $data['nextday']);
 
-                static::assertArrayHasKey('linksToDisplay', $data);
-                static::assertCount(3, $data['linksToDisplay']);
-                static::assertSame(1, $data['linksToDisplay'][0]['id']);
-                static::assertSame($currentDay->getTimestamp(), $data['day']);
-                static::assertSame('20200510', $data['previousday']);
-                static::assertSame('20200516', $data['nextday']);
-
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -203,19 +204,20 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_daily'])
             ->willReturnCallback(function (string $hook, array $data, array $param) use ($currentDay): array {
-                static::assertSame('render_daily', $hook);
-
-                static::assertArrayHasKey('linksToDisplay', $data);
-                static::assertCount(1, $data['linksToDisplay']);
-                static::assertSame(1, $data['linksToDisplay'][0]['id']);
-                static::assertSame($currentDay->getTimestamp(), $data['day']);
-                static::assertEmpty($data['previousday']);
-                static::assertEmpty($data['nextday']);
+                if ('render_daily' === $hook) {
+                    static::assertArrayHasKey('linksToDisplay', $data);
+                    static::assertCount(1, $data['linksToDisplay']);
+                    static::assertSame(1, $data['linksToDisplay'][0]['id']);
+                    static::assertSame($currentDay->getTimestamp(), $data['day']);
+                    static::assertEmpty($data['previousday']);
+                    static::assertEmpty($data['nextday']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             });
@@ -281,7 +283,7 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
                 return $data;
@@ -333,7 +335,7 @@ class DailyControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
                 return $data;
@@ -392,8 +394,8 @@ class DailyControllerTest extends TestCase
         static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
         static::assertSame('dailyrss', (string) $result->getBody());
         static::assertSame('Shaarli', $assignedVariables['title']);
-        static::assertSame('http://shaarli', $assignedVariables['index_url']);
-        static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
+        static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
+        static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
         static::assertFalse($assignedVariables['hide_timestamps']);
         static::assertCount(2, $assignedVariables['days']);
 
@@ -402,7 +404,7 @@ class DailyControllerTest extends TestCase
         static::assertEquals($dates[0], $day['date']);
         static::assertSame($dates[0]->format(\DateTime::RSS), $day['date_rss']);
         static::assertSame(format_date($dates[0], false), $day['date_human']);
-        static::assertSame('http://shaarli/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
+        static::assertSame('http://shaarli/subfolder/daily?day='. $dates[0]->format('Ymd'), $day['absolute_url']);
         static::assertCount(1, $day['links']);
         static::assertSame(1, $day['links'][0]['id']);
         static::assertSame('http://domain.tld/1', $day['links'][0]['url']);
@@ -413,7 +415,7 @@ class DailyControllerTest extends TestCase
         static::assertEquals($dates[1], $day['date']);
         static::assertSame($dates[1]->format(\DateTime::RSS), $day['date_rss']);
         static::assertSame(format_date($dates[1], false), $day['date_human']);
-        static::assertSame('http://shaarli/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
+        static::assertSame('http://shaarli/subfolder/daily?day='. $dates[1]->format('Ymd'), $day['absolute_url']);
         static::assertCount(2, $day['links']);
 
         static::assertSame(2, $day['links'][0]['id']);
@@ -468,8 +470,8 @@ class DailyControllerTest extends TestCase
         static::assertStringContainsString('application/rss', $result->getHeader('Content-Type')[0]);
         static::assertSame('dailyrss', (string) $result->getBody());
         static::assertSame('Shaarli', $assignedVariables['title']);
-        static::assertSame('http://shaarli', $assignedVariables['index_url']);
-        static::assertSame('http://shaarli/daily-rss', $assignedVariables['page_url']);
+        static::assertSame('http://shaarli/subfolder/', $assignedVariables['index_url']);
+        static::assertSame('http://shaarli/subfolder/daily-rss', $assignedVariables['page_url']);
         static::assertFalse($assignedVariables['hide_timestamps']);
         static::assertCount(0, $assignedVariables['days']);
     }
index e497bfefb874bfcac6206b32292e785480b1c7b2..75408cf4040e21297f049729213a63b21f915a3c 100644 (file)
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Exception\ShaarliFrontException;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
diff --git a/tests/front/controller/visitor/ErrorNotFoundControllerTest.php b/tests/front/controller/visitor/ErrorNotFoundControllerTest.php
new file mode 100644 (file)
index 0000000..a1cbbec
--- /dev/null
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Front\Controller\Visitor;
+
+use Shaarli\TestCase;
+use Slim\Http\Request;
+use Slim\Http\Response;
+use Slim\Http\Uri;
+
+class ErrorNotFoundControllerTest extends TestCase
+{
+    use FrontControllerMockHelper;
+
+    /** @var ErrorNotFoundController */
+    protected $controller;
+
+    public function setUp(): void
+    {
+        $this->createContainer();
+
+        $this->controller = new ErrorNotFoundController($this->container);
+    }
+
+    /**
+     * Test displaying 404 error
+     */
+    public function testDisplayNotFoundError(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->expects(static::once())->method('getRequestTarget')->willReturn('/');
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+
+        // Save RainTPL assigned variables
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $result = ($this->controller)(
+            $request,
+            $response
+        );
+
+        static::assertSame(404, $result->getStatusCode());
+        static::assertSame('404', (string) $result->getBody());
+        static::assertSame('Requested page could not be found.', $assignedVariables['error_message']);
+    }
+
+    /**
+     * Test displaying 404 error from REST API
+     */
+    public function testDisplayNotFoundErrorFromAPI(): void
+    {
+        $request = $this->createMock(Request::class);
+        $request->expects(static::once())->method('getRequestTarget')->willReturn('/sufolder/api/v1/links');
+        $request->method('getUri')->willReturnCallback(function (): Uri {
+            $uri = $this->createMock(Uri::class);
+            $uri->method('getBasePath')->willReturn('/subfolder');
+
+            return $uri;
+        });
+
+        $response = new Response();
+
+        // Save RainTPL assigned variables
+        $assignedVariables = [];
+        $this->assignTemplateVars($assignedVariables);
+
+        $result = ($this->controller)($request, $response);
+
+        static::assertSame(404, $result->getStatusCode());
+        static::assertSame([], $assignedVariables);
+    }
+}
index fb417e2a2b152f1a6c52e166c275afda7ab1e190..4ae7c9252913a6c36719dbd117ef0954358b5447 100644 (file)
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Feed\FeedBuilder;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -45,14 +45,16 @@ class FeedControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_feed'])
             ->willReturnCallback(function (string $hook, array $data, array $param): void {
-                static::assertSame('render_feed', $hook);
-                static::assertSame('data', $data['content']);
+                if ('render_feed' === $hook) {
+                    static::assertSame('data', $data['content']);
 
-                static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('rss', $param['target']);
+                    static::assertArrayHasKey('loggedin', $param);
+                    static::assertSame('feed.rss', $param['target']);
+                }
             })
         ;
 
@@ -84,14 +86,16 @@ class FeedControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_feed'])
             ->willReturnCallback(function (string $hook, array $data, array $param): void {
-                static::assertSame('render_feed', $hook);
-                static::assertSame('data', $data['content']);
+                if ('render_feed' === $hook) {
+                    static::assertSame('data', $data['content']);
 
-                static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('atom', $param['target']);
+                    static::assertArrayHasKey('loggedin', $param);
+                    static::assertSame('feed.atom', $param['target']);
+                }
             })
         ;
 
@@ -124,14 +128,16 @@ class FeedControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_feed'])
             ->willReturnCallback(function (string $hook, array $data, array $param): void {
-                static::assertSame('render_feed', $hook);
-                static::assertSame('data', $data['content']);
+                if ('render_feed' === $hook) {
+                    static::assertSame('data', $data['content']);
 
-                static::assertArrayHasKey('loggedin', $param);
-                static::assertSame('atom', $param['target']);
+                    static::assertArrayHasKey('loggedin', $param);
+                    static::assertSame('feed.atom', $param['target']);
+                }
             })
         ;
 
index e0bd4ecf5d14cd426546caf94893873f75c55fc2..fc0bb7d1a3cc123424674c40070601ec241bb0d6 100644 (file)
@@ -4,7 +4,6 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\MockObject\MockObject;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Container\ShaarliTestContainer;
@@ -79,8 +78,9 @@ trait FrontControllerMockHelper
         $this->container->environment = [
             'SERVER_NAME' => 'shaarli',
             'SERVER_PORT' => '80',
-            'REQUEST_URI' => '/daily-rss',
+            'REQUEST_URI' => '/subfolder/daily-rss',
             'REMOTE_ADDR' => '1.2.3.4',
+            'SCRIPT_NAME' => '/subfolder/index.php',
         ];
 
         $this->container->basePath = '/subfolder';
@@ -94,7 +94,6 @@ trait FrontControllerMockHelper
     protected function assignTemplateVars(array &$variables): void
     {
         $this->container->pageBuilder
-            ->expects(static::atLeastOnce())
             ->method('assign')
             ->willReturnCallback(function ($key, $value) use (&$variables) {
                 $variables[$key] = $value;
@@ -115,5 +114,5 @@ trait FrontControllerMockHelper
     /**
      * Force to be used in PHPUnit context.
      */
-    protected abstract function createMock($originalClassName): MockObject;
+    protected abstract function isInTestsContext(): bool;
 }
index 3b855365024a9e9e8462299ed5e1e85a74449aaf..345ad544b85a582ccfab88b9f1a9ad4e74375843 100644 (file)
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\AlreadyInstalledException;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -257,6 +257,39 @@ class InstallControllerTest extends TestCase
         static::assertSame('/subfolder/login', $result->getHeader('location')[0]);
 
         static::assertSame('UTC', $confSettings['general.timezone']);
-        static::assertSame('Shared bookmarks on http://shaarli', $confSettings['general.title']);
+        static::assertSame('Shared bookmarks on http://shaarli/subfolder/', $confSettings['general.title']);
+    }
+
+    /**
+     * Same test  as testSaveInstallDefaultValues() but for an instance install in root directory.
+     */
+    public function testSaveInstallDefaultValuesWithoutSubfolder(): void
+    {
+        $confSettings = [];
+
+        $this->container->environment = [
+            'SERVER_NAME' => 'shaarli',
+            'SERVER_PORT' => '80',
+            'REQUEST_URI' => '/install',
+            'REMOTE_ADDR' => '1.2.3.4',
+            'SCRIPT_NAME' => '/index.php',
+        ];
+
+        $this->container->basePath = '';
+
+        $request = $this->createMock(Request::class);
+        $response = new Response();
+
+        $this->container->conf->method('set')->willReturnCallback(function (string $key, $value) use (&$confSettings) {
+            $confSettings[$key] = $value;
+        });
+
+        $result = $this->controller->save($request, $response);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame('/login', $result->getHeader('location')[0]);
+
+        static::assertSame('UTC', $confSettings['general.timezone']);
+        static::assertSame('Shared bookmarks on http://shaarli/', $confSettings['general.title']);
     }
 }
index 0a21f9385ea4996ddb762cc69764eeefb5f2ea88..1312ccb79199c1620651e805ffdded4bd71a838a 100644 (file)
@@ -4,13 +4,13 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\LoginBannedException;
 use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Render\TemplatePage;
 use Shaarli\Security\CookieManager;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 5f9f5b1285c42eb72200710a24d8f2fa26c0cd7e..42d876c36b0c0352be527e75c4119969c57b3981 100644 (file)
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -39,6 +39,6 @@ class OpenSearchControllerTest extends TestCase
             $result->getHeader('Content-Type')[0]
         );
         static::assertSame('opensearch', (string) $result->getBody());
-        static::assertSame('http://shaarli', $assignedVariables['serverurl']);
+        static::assertSame('http://shaarli/subfolder/', $assignedVariables['serverurl']);
     }
 }
index 3dc3f292e3421467e5cc5584450d4f42ff5cae4a..b868231dc92aaefebdd19bcebaff9c07320b6cc7 100644 (file)
@@ -4,10 +4,10 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Front\Exception\ThumbnailsDisabledException;
+use Shaarli\TestCase;
 use Shaarli\Thumbnailer;
 use Slim\Http\Request;
 use Slim\Http\Response;
@@ -67,15 +67,17 @@ class PictureWallControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_picwall'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_picwall', $hook);
-                static::assertArrayHasKey('linksToDisplay', $data);
-                static::assertCount(2, $data['linksToDisplay']);
-                static::assertSame(1, $data['linksToDisplay'][0]['id']);
-                static::assertSame(3, $data['linksToDisplay'][1]['id']);
-                static::assertArrayHasKey('loggedin', $param);
+                if ('render_picwall' === $hook) {
+                    static::assertArrayHasKey('linksToDisplay', $data);
+                    static::assertCount(2, $data['linksToDisplay']);
+                    static::assertSame(1, $data['linksToDisplay'][0]['id']);
+                    static::assertSame(3, $data['linksToDisplay'][1]['id']);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             });
index 0635275089cb7661dfde3abf8073d6682788ad41..7e3b00afae4b27616ef3fd587dee9f480b112b61 100644 (file)
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -28,7 +28,7 @@ class PublicSessionFilterControllerTest extends TestCase
      */
     public function testLinksPerPage(): void
     {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $request = $this->createMock(Request::class);
         $request->method('getParam')->with('nb')->willReturn('8');
@@ -74,7 +74,7 @@ class PublicSessionFilterControllerTest extends TestCase
      */
     public function testUntaggedOnly(): void
     {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $request = $this->createMock(Request::class);
         $response = new Response();
@@ -97,7 +97,7 @@ class PublicSessionFilterControllerTest extends TestCase
      */
     public function testUntaggedOnlyToggleOff(): void
     {
-        $this->container->environment = ['HTTP_REFERER' => 'http://shaarli/subfolder/controller/?searchtag=abc'];
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller/?searchtag=abc';
 
         $request = $this->createMock(Request::class);
         $response = new Response();
index 316ce49c021114d667d16d3a84942adf629d18ab..935ec24ef7597ad67dcf043176883d3f571f9995 100644 (file)
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFilter;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -110,7 +110,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererDefault(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -125,7 +125,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithUnmatchedLoopTerm(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -140,7 +140,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingLoopTermInPath(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -155,7 +155,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingLoopTermInQueryParam(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -171,7 +171,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingLoopTermInQueryValue(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -187,7 +187,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithLoopTermInDomain(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -203,7 +203,7 @@ class ShaarliVisitorControllerTest extends TestCase
      */
     public function testRedirectFromRefererWithMatchingClearedParam(): void
     {
-        $this->container->environment['HTTP_REFERER'] = 'http://shaarli.tld/subfolder/controller?query=param&other=2';
+        $this->container->environment['HTTP_REFERER'] = 'http://shaarli/subfolder/controller?query=param&other=2';
 
         $response = new Response();
 
@@ -212,4 +212,35 @@ class ShaarliVisitorControllerTest extends TestCase
         static::assertSame(302, $result->getStatusCode());
         static::assertSame(['/subfolder/controller?other=2'], $result->getHeader('location'));
     }
+
+    /**
+     * Test redirectFromReferer() - From another domain -> we ignore the given referrer.
+     */
+    public function testRedirectExternalReferer(): void
+    {
+        $this->container->environment['HTTP_REFERER'] = 'http://other.domain.tld/controller?query=param&other=2';
+
+        $response = new Response();
+
+        $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/'], $result->getHeader('location'));
+    }
+
+    /**
+     * Test redirectFromReferer() - From another domain -> we ignore the given referrer.
+     */
+    public function testRedirectExternalRefererExplicitDomainName(): void
+    {
+        $this->container->environment['SERVER_NAME'] = 'my.shaarli.tld';
+        $this->container->environment['HTTP_REFERER'] = 'http://your.shaarli.tld/controller?query=param&other=2';
+
+        $response = new Response();
+
+        $result = $this->controller->redirectFromReferer($this->request, $response, ['query'], ['query']);
+
+        static::assertSame(302, $result->getStatusCode());
+        static::assertSame(['/subfolder/'], $result->getHeader('location'));
+    }
 }
index 9a6a4bc008c386bad89f53d80b4d6ffa6417678d..9305612ed484dbbef775567d39c46a3b8fce7c5b 100644 (file)
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFilter;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -53,14 +53,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_tagcloud'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_tagcloud', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(3, $data['tags']);
+                if ('render_tagcloud' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(3, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -124,14 +126,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_tagcloud'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_tagcloud', $hook);
-                static::assertSame('ghi def', $data['search_tags']);
-                static::assertCount(1, $data['tags']);
+               if ('render_tagcloud' === $hook) {
+                   static::assertSame('ghi def', $data['search_tags']);
+                   static::assertCount(1, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                   static::assertArrayHasKey('loggedin', $param);
+               }
 
                 return $data;
             })
@@ -175,14 +179,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_tagcloud'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_tagcloud', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(0, $data['tags']);
+                if ('render_tagcloud' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(0, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -227,14 +233,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_taglist'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_taglist', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(3, $data['tags']);
+                if ('render_taglist' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(3, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -297,14 +305,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_taglist'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_taglist', $hook);
-                static::assertSame('ghi def', $data['search_tags']);
-                static::assertCount(1, $data['tags']);
+                if ('render_taglist' === $hook) {
+                    static::assertSame('ghi def', $data['search_tags']);
+                    static::assertCount(1, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
@@ -344,14 +354,16 @@ class TagCloudControllerTest extends TestCase
 
         // Make sure that PluginManager hook is triggered
         $this->container->pluginManager
-            ->expects(static::at(0))
+            ->expects(static::atLeastOnce())
             ->method('executeHooks')
+            ->withConsecutive(['render_taglist'])
             ->willReturnCallback(function (string $hook, array $data, array $param): array {
-                static::assertSame('render_taglist', $hook);
-                static::assertSame('', $data['search_tags']);
-                static::assertCount(0, $data['tags']);
+                if ('render_taglist' === $hook) {
+                    static::assertSame('', $data['search_tags']);
+                    static::assertCount(0, $data['tags']);
 
-                static::assertArrayHasKey('loggedin', $param);
+                    static::assertArrayHasKey('loggedin', $param);
+                }
 
                 return $data;
             })
index 43076086999dc9e8ee08f606ef4bed4731dbc32b..750ea02d85c47aea9f5f566089c1b8a9aaf94543 100644 (file)
@@ -4,7 +4,7 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 982e57e0b6ff37ae8b42b1a5a11707ddf0bb08b9..3a0fcf30c084ffdaa2d80c5232d7fcd9583112f9 100644 (file)
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for client_ip_id()
  */
-class ClientIpIdTest extends \PHPUnit\Framework\TestCase
+class ClientIpIdTest extends \Shaarli\TestCase
 {
     /**
      * Get a remote client ID based on its IP
index 3dc5bc9b03c38c9b0cad7763b2578b6e0ed017c5..a868ac0225d1c3e86a869f23dbe6f9bb5b23c284 100644 (file)
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for get_http_response()
  */
-class GetHttpUrlTest extends \PHPUnit\Framework\TestCase
+class GetHttpUrlTest extends \Shaarli\TestCase
 {
     /**
      * Get an invalid local URL
index fe3a639e296ed3fe6512c7186f43f9d49fb7694c..60cdb9927130a3689ba63145bd8d766c19ba1592 100644 (file)
@@ -7,7 +7,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for getIpAddressFromProxy()
  */
-class GetIpAdressFromProxyTest extends \PHPUnit\Framework\TestCase
+class GetIpAdressFromProxyTest extends \Shaarli\TestCase
 {
 
     /**
index 73d33cd450d783237829c133641783b5715243b3..f283d119e388404bd4864f72675fb4d52cf334bd 100644 (file)
@@ -5,12 +5,14 @@
 
 namespace Shaarli\Http;
 
+use Shaarli\TestCase;
+
 require_once 'application/http/HttpUtils.php';
 
 /**
  * Unitary tests for index_url()
  */
-class IndexUrlTest extends \PHPUnit\Framework\TestCase
+class IndexUrlTest extends TestCase
 {
     /**
      * If on the main page, remove "index.php" from the URL resource
@@ -103,4 +105,36 @@ class IndexUrlTest extends \PHPUnit\Framework\TestCase
             )
         );
     }
+
+    /**
+     * The route is stored in REQUEST_URI and subfolder
+     */
+    public function testPageUrlWithRouteUnderSubfolder()
+    {
+        $this->assertEquals(
+            'http://host.tld/subfolder/picture-wall',
+            page_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/subfolder/index.php',
+                    'REQUEST_URI' => '/subfolder/picture-wall',
+                )
+            )
+        );
+
+        $this->assertEquals(
+            'http://host.tld/subfolder/admin/picture-wall',
+            page_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/subfolder/admin/index.php',
+                    'REQUEST_URI' => '/subfolder/admin/picture-wall',
+                )
+            )
+        );
+    }
 }
diff --git a/tests/http/HttpUtils/IndexUrlTestWithConstant.php b/tests/http/HttpUtils/IndexUrlTestWithConstant.php
new file mode 100644 (file)
index 0000000..ecaea72
--- /dev/null
@@ -0,0 +1,51 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Shaarli\Http;
+
+use Shaarli\TestCase;
+
+/**
+ * Test index_url with SHAARLI_ROOT_URL defined to override automatic retrieval.
+ * This should stay in its dedicated class to make sure to not alter other tests of the suite.
+ */
+class IndexUrlTestWithConstant extends TestCase
+{
+    public static function setUpBeforeClass(): void
+    {
+        define('SHAARLI_ROOT_URL', 'http://other-host.tld/subfolder/');
+    }
+
+    /**
+     * The route is stored in REQUEST_URI and subfolder
+     */
+    public function testIndexUrlWithConstantDefined()
+    {
+        $this->assertEquals(
+            'http://other-host.tld/subfolder/',
+            index_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/index.php',
+                    'REQUEST_URI' => '/picture-wall',
+                )
+            )
+        );
+
+        $this->assertEquals(
+            'http://other-host.tld/subfolder/',
+            index_url(
+                array(
+                    'HTTPS' => 'Off',
+                    'SERVER_NAME' => 'host.tld',
+                    'SERVER_PORT' => '80',
+                    'SCRIPT_NAME' => '/admin/index.php',
+                    'REQUEST_URI' => '/admin/picture-wall',
+                )
+            )
+        );
+    }
+}
index 348956c645e6c40891ab42655237e75d7b810403..8b3fd93dbfb38130513c3257a2d64a17f8267a15 100644 (file)
@@ -9,7 +9,7 @@ require_once 'application/http/HttpUtils.php';
  *
  * Test class for is_https() function.
  */
-class IsHttpsTest extends \PHPUnit\Framework\TestCase
+class IsHttpsTest extends \Shaarli\TestCase
 {
 
     /**
index f199171684bad9694e6d3545b13b2a55c14d14ef..ebb3e617bd0584d6d1126104fa1e1c013095cf8b 100644 (file)
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for page_url()
  */
-class PageUrlTest extends \PHPUnit\Framework\TestCase
+class PageUrlTest extends \Shaarli\TestCase
 {
     /**
      * If on the main page, remove "index.php" from the URL resource
index 9caf104983ffd75427cb6a9a9c35cb1a29f042d0..339664e1720bc080bc0252669bbb4eb3baefb37b 100644 (file)
@@ -10,7 +10,7 @@ require_once 'application/http/HttpUtils.php';
 /**
  * Unitary tests for server_url()
  */
-class ServerUrlTest extends \PHPUnit\Framework\TestCase
+class ServerUrlTest extends \Shaarli\TestCase
 {
     /**
      * Detect if the server uses SSL
index ae92f73a4d4a2a62a851b9d99d5b523bc9b303e7..c6b39c29753b47f23ac521ec824a4f9165e9e21e 100644 (file)
@@ -8,7 +8,7 @@ namespace Shaarli\Http;
 /**
  * Unitary tests for URL utilities
  */
-class UrlTest extends \PHPUnit\Framework\TestCase
+class UrlTest extends \Shaarli\TestCase
 {
     // base URL for tests
     protected static $baseUrl = 'http://domain.tld:3000';
index 6c4d124bed845f4d5205dda31df2f61b0a0d99d0..45690ecfb196e46b2aa90b110d8877d63611fb7b 100644 (file)
@@ -7,7 +7,7 @@ namespace Shaarli\Http;
 
 require_once 'application/http/UrlUtils.php';
 
-class CleanupUrlTest extends \PHPUnit\Framework\TestCase
+class CleanupUrlTest extends \Shaarli\TestCase
 {
     /**
      * @var string reference URL
index 2b97f7be649a4c120fb31c24f13ab19f70b7c3a1..18a9a5e50691f768cbe593f0bde8a83e233dc0cc 100644 (file)
@@ -7,7 +7,7 @@ namespace Shaarli\Http;
 
 require_once 'application/http/UrlUtils.php';
 
-class GetUrlSchemeTest extends \PHPUnit\Framework\TestCase
+class GetUrlSchemeTest extends \Shaarli\TestCase
 {
     /**
      * Get empty scheme string for empty UrlUtils
index 040d8c54ed5a1fca14490ec36ebdb2994005252f..5e6246cceef2c1550b0ba2ff5f707835965902e7 100644 (file)
@@ -10,7 +10,7 @@ require_once 'application/http/UrlUtils.php';
 /**
  * Unitary tests for unparse_url()
  */
-class UnparseUrlTest extends \PHPUnit\Framework\TestCase
+class UnparseUrlTest extends \Shaarli\TestCase
 {
     /**
      * Thanks for building nothing
index 69512dbd18787a2129b83c97662cf31fbba91f9a..b8a6baaa769118dda0272a996f6e5deccc57f729 100644 (file)
@@ -9,7 +9,7 @@ require_once 'application/http/UrlUtils.php';
  *
  * Test whitelist_protocols() function of UrlUtils.
  */
-class WhitelistProtocolsTest extends \PHPUnit\Framework\TestCase
+class WhitelistProtocolsTest extends \Shaarli\TestCase
 {
     /**
      * Test whitelist_protocols() on a note (relative URL).
index b8b7ca3a548358e98946e5d8833b748a40ecf27c..d84feed135366f3e122785839d24f2eb9dd93e2d 100644 (file)
@@ -12,7 +12,7 @@ use Shaarli\Config\ConfigManager;
  *
  * @package Shaarli
  */
-class LanguagesFrTest extends \PHPUnit\Framework\TestCase
+class LanguagesFrTest extends \Shaarli\TestCase
 {
     /**
      * @var string Config file path (without extension).
@@ -27,7 +27,7 @@ class LanguagesFrTest extends \PHPUnit\Framework\TestCase
     /**
      * Init: force French
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new ConfigManager(self::$configFile);
         $this->conf->set('translation.language', 'fr');
@@ -36,7 +36,7 @@ class LanguagesFrTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset the locale since gettext seems to mess with it, making it too long
      */
-    public static function tearDownAfterClass()
+    public static function tearDownAfterClass(): void
     {
         if (! empty(getenv('UT_LOCALE'))) {
             setlocale(LC_ALL, getenv('UT_LOCALE'));
index 4e52f3e186597375b351d575c1067b9a7dbd7573..1a2549a377eff1838d8b68d094f3df1e32b34592 100644 (file)
@@ -4,8 +4,8 @@ declare(strict_types=1);
 
 namespace Shaarli\Legacy;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Front\Controller\Visitor\FrontControllerMockHelper;
+use Shaarli\TestCase;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
index 0884ad03ed2bd40837bc08ac4d1d60adb28820f6..df2cad62295594145843eac725bff46bec8068e3 100644 (file)
@@ -18,7 +18,7 @@ require_once 'tests/utils/ReferenceLinkDB.php';
 /**
  * Unitary tests for LegacyLinkDBTest
  */
-class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
+class LegacyLinkDBTest extends \Shaarli\TestCase
 {
     // datastore to test write operations
     protected static $testDatastore = 'sandbox/datastore.php';
@@ -52,7 +52,7 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
      *
      * Resets test data for each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
@@ -99,12 +99,12 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Attempt to instantiate a LinkDB whereas the datastore is not writable
-     *
-     * @expectedException              Shaarli\Exceptions\IOException
-     * @expectedExceptionMessageRegExp /Error accessing "null"/
      */
     public function testConstructDatastoreNotWriteable()
     {
+        $this->expectException(\Shaarli\Exceptions\IOException::class);
+        $this->expectExceptionMessageRegExp('/Error accessing "null"/');
+
         new LegacyLinkDB('null/store.db', false, false);
     }
 
@@ -257,7 +257,7 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
         $link = self::$publicLinkDB->getLinkFromUrl('http://mediagoblin.org/');
 
         $this->assertNotEquals(false, $link);
-        $this->assertContains(
+        $this->assertContainsPolyfill(
             'A free software media publishing platform',
             $link['description']
         );
@@ -420,22 +420,22 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test filterHash() with an invalid smallhash.
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterHashInValid1()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         $request = 'blabla';
         self::$publicLinkDB->filterHash($request);
     }
 
     /**
      * Test filterHash() with an empty smallhash.
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterHashInValid()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         self::$publicLinkDB->filterHash('');
     }
 
@@ -470,9 +470,9 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
         $res = $linkDB->renameTag('cartoon', 'Taz');
         $this->assertEquals(3, count($res));
-        $this->assertContains(' Taz ', $linkDB[4]['tags']);
-        $this->assertContains(' Taz ', $linkDB[1]['tags']);
-        $this->assertContains(' Taz ', $linkDB[0]['tags']);
+        $this->assertContainsPolyfill(' Taz ', $linkDB[4]['tags']);
+        $this->assertContainsPolyfill(' Taz ', $linkDB[1]['tags']);
+        $this->assertContainsPolyfill(' Taz ', $linkDB[0]['tags']);
     }
 
     /**
@@ -512,7 +512,7 @@ class LegacyLinkDBTest extends \PHPUnit\Framework\TestCase
 
         $res = $linkDB->renameTag('cartoon', null);
         $this->assertEquals(3, count($res));
-        $this->assertNotContains('cartoon', $linkDB[4]['tags']);
+        $this->assertNotContainsPolyfill('cartoon', $linkDB[4]['tags']);
     }
 
     /**
index ba9ec529bf208a1dcb6a5f98accea7ad0c909048..45d7754d34a82cd5ff22fe52f12663c268bd3c46 100644 (file)
@@ -10,7 +10,7 @@ use Shaarli\Legacy\LegacyLinkFilter;
 /**
  * Class LegacyLinkFilterTest.
  */
-class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
+class LegacyLinkFilterTest extends \Shaarli\TestCase
 {
     /**
      * @var string Test datastore path.
@@ -34,7 +34,7 @@ class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
     /**
      * Instantiate linkFilter with ReferenceLinkDB data.
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$refDB = new ReferenceLinkDB(true);
         self::$refDB->write(self::$testDatastore);
@@ -197,21 +197,23 @@ class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayWithChars()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, 'Rainy day, dream away');
     }
 
     /**
      * Use an invalid date format
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid date format/
      */
     public function testFilterInvalidDayDigits()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Invalid date format/');
+
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_DAY, '20');
     }
 
@@ -235,11 +237,11 @@ class LegacyLinkFilterTest extends \PHPUnit\Framework\TestCase
 
     /**
      * No link for this hash
-     *
-     * @expectedException \Shaarli\Bookmark\Exception\BookmarkNotFoundException
      */
     public function testFilterUnknownSmallHash()
     {
+        $this->expectException(\Shaarli\Bookmark\Exception\BookmarkNotFoundException::class);
+
         self::$linkFilter->filter(LegacyLinkFilter::$FILTER_HASH, 'Iblaah');
     }
 
diff --git a/tests/legacy/LegacyRouterTest.php b/tests/legacy/LegacyRouterTest.php
deleted file mode 100644 (file)
index c2019ca..0000000
+++ /dev/null
@@ -1,512 +0,0 @@
-<?php
-
-namespace Shaarli\Legacy;
-
-use PHPUnit\Framework\TestCase;
-
-/**
- * Unit tests for Router
- */
-class LegacyRouterTest extends TestCase
-{
-    /**
-     * Test findPage: login page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageLoginValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login', array(), 1)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login&stuff', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: login page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageLoginInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=login', array(), true)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_LOGIN,
-            LegacyRouter::findPage('do=other', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: picwall page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPagePicwallValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=picwall', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=picwall', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: picwall page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPagePicwallInvalid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=picwall&stuff', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_PICWALL,
-            LegacyRouter::findPage('do=other', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: tagcloud page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageTagcloudValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=tagcloud', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=tagcloud', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=tagcloud&stuff', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: tagcloud page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageTagcloudInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TAGCLOUD,
-            LegacyRouter::findPage('do=other', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: linklist page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageLinklistValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('whatever', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('whatever', array(), false)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_LINKLIST,
-            LegacyRouter::findPage('do=tools', array(), false)
-        );
-    }
-
-    /**
-     * Test findPage: tools page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageToolsValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: tools page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageToolsInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=tools', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_TOOLS,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changepasswd page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangepasswdValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd', array(), true)
-        );
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changepasswd page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangepasswdInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=changepasswd', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGEPASSWORD,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-    /**
-     * Test findPage: configure page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageConfigureValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: configure page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageConfigureInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=configure', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CONFIGURE,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changetag page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangetagValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: changetag page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageChangetagInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=changetag', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_CHANGETAG,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: addlink page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageAddlinkValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: addlink page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageAddlinkInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=addlink', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_ADDLINK,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: export page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageExportValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: export page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageExportInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=export', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EXPORT,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: import page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageImportValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import', array(), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import&stuff', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: import page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageImportInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import', array(), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=import', array(), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_IMPORT,
-            LegacyRouter::findPage('do=other', array(), true)
-        );
-    }
-
-    /**
-     * Test findPage: editlink page output.
-     * Valid: page should be return.
-     *
-     * @return void
-     */
-    public function testFindPageEditlinkValid()
-    {
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('edit_link' => 1), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('', array('edit_link' => 1), true)
-        );
-
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('post' => 1), true)
-        );
-
-        $this->assertEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('post' => 1, 'edit_link' => 1), true)
-        );
-    }
-
-    /**
-     * Test findPage: editlink page output.
-     * Invalid: page shouldn't be return.
-     *
-     * @return void
-     */
-    public function testFindPageEditlinkInvalid()
-    {
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('edit_link' => 1), false)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array('edit_link' => 1), 1)
-        );
-
-        $this->assertNotEquals(
-            LegacyRouter::$PAGE_EDITLINK,
-            LegacyRouter::findPage('whatever', array(), true)
-        );
-    }
-}
index 7c429811bb917a3fabaacd3adcc36f7b615b81ac..f7391b867f593efd932aba8ae66f46ab6a1685fd 100644 (file)
@@ -20,7 +20,7 @@ require_once 'inc/rain.tpl.class.php';
  * Class UpdaterTest.
  * Runs unit tests against the updater class.
  */
-class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
+class LegacyUpdaterTest extends \Shaarli\TestCase
 {
     /**
      * @var string Path to test datastore.
@@ -40,7 +40,7 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
     /**
      * Executed before each test.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         copy('tests/utils/config/configJson.json.php', self::$configFile .'.json.php');
         $this->conf = new ConfigManager(self::$configFile);
@@ -80,23 +80,23 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): empty updates file.
-     *
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/
      */
     public function testWriteEmptyUpdatesFile()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
+
         UpdaterUtils::write_updates_file('', array('test'));
     }
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): not writable updates file.
-     *
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Unable to write(.*)/
      */
     public function testWriteUpdatesFileNotWritable()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Unable to write(.*)/');
+
         $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
         touch($updatesFile);
         chmod($updatesFile, 0444);
@@ -161,11 +161,11 @@ class LegacyUpdaterTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test Update failed.
-     *
-     * @expectedException \Exception
      */
     public function testUpdateFailed()
     {
+        $this->expectException(\Exception::class);
+
         $updates = array(
             'updateMethodDummy1',
             'updateMethodDummy2',
@@ -723,7 +723,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         $this->assertEquals(\Shaarli\Thumbnailer::MODE_ALL, $this->conf->get('thumbnails.mode'));
         $this->assertEquals(125, $this->conf->get('thumbnails.width'));
         $this->assertEquals(90, $this->conf->get('thumbnails.height'));
-        $this->assertContains('You have enabled or changed thumbnails', $_SESSION['warnings'][0]);
+        $this->assertContainsPolyfill('You have enabled or changed thumbnails', $_SESSION['warnings'][0]);
     }
 
     /**
@@ -754,7 +754,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         if (isset($_SESSION['warnings'])) {
             unset($_SESSION['warnings']);
         }
-        
+
         $updater = new LegacyUpdater([], [], $this->conf, true, $_SESSION);
         $this->assertTrue($updater->updateMethodWebThumbnailer());
         $this->assertFalse($this->conf->exists('thumbnail'));
index 509da51d8ad2e576546b018b14671034bd901af2..9b95ccc9eaf9338fbbed007ef63b1f300450ed6a 100644 (file)
@@ -2,12 +2,12 @@
 
 namespace Shaarli\Netscape;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Formatter\BookmarkFormatter;
 use Shaarli\Formatter\FormatterFactory;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 require_once 'tests/utils/ReferenceLinkDB.php';
 
@@ -54,7 +54,7 @@ class BookmarkExportTest extends TestCase
     /**
      * Instantiate reference data
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         static::$conf = new ConfigManager('tests/utils/config/configJson');
         static::$conf->set('resource.datastore', static::$testDatastore);
@@ -77,11 +77,12 @@ class BookmarkExportTest extends TestCase
 
     /**
      * Attempt to export an invalid link selection
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Invalid export selection/
      */
     public function testFilterAndFormatInvalid()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Invalid export selection/');
+
         $this->netscapeBookmarkUtils->filterAndFormat(
             self::$formatter,
             'derp',
index f678e26bd5ca8d3199242d33f6613bb36f7afecc..c1e49b5f454584fe0b29272e455e991656d3e8e5 100644 (file)
@@ -3,13 +3,13 @@
 namespace Shaarli\Netscape;
 
 use DateTime;
-use PHPUnit\Framework\TestCase;
 use Psr\Http\Message\UploadedFileInterface;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkFilter;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 use Slim\Http\UploadedFile;
 
 /**
@@ -75,7 +75,7 @@ class BookmarkImportTest extends TestCase
      */
     protected static $defaultTimeZone;
 
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$defaultTimeZone = date_default_timezone_get();
         // Timezone without DST for test consistency
@@ -85,7 +85,7 @@ class BookmarkImportTest extends TestCase
     /**
      * Resets test data before each test
      */
-    protected function setUp()
+    protected function setUp(): void
     {
         if (file_exists(self::$testDatastore)) {
             unlink(self::$testDatastore);
@@ -104,12 +104,12 @@ class BookmarkImportTest extends TestCase
     /**
      * Delete history file.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         @unlink(self::$historyFilePath);
     }
 
-    public static function tearDownAfterClass()
+    public static function tearDownAfterClass(): void
     {
         date_default_timezone_set(self::$defaultTimeZone);
     }
index aa5c6988f639da5c9e8097897bdf151fa0b1b960..a3ec9fc9d28c6e51aa015cfb75838e65b2849525 100644 (file)
@@ -9,12 +9,12 @@ require_once 'plugins/addlink_toolbar/addlink_toolbar.php';
 /**
  * Unit test for the Addlink toolbar plugin
  */
-class PluginAddlinkTest extends \PHPUnit\Framework\TestCase
+class PluginAddlinkTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
index b9a67adb5aac4bc207b1a7c325bac36639546d1b..467dc3d030583bed63a7382e6ea3afdd79f5be50 100644 (file)
@@ -1,4 +1,5 @@
 <?php
+
 namespace Shaarli\Plugin\Archiveorg;
 
 /**
@@ -6,6 +7,7 @@ namespace Shaarli\Plugin\Archiveorg;
  */
 
 use Shaarli\Plugin\PluginManager;
+use Shaarli\TestCase;
 
 require_once 'plugins/archiveorg/archiveorg.php';
 
@@ -13,20 +15,35 @@ require_once 'plugins/archiveorg/archiveorg.php';
  * Class PluginArchiveorgTest
  * Unit test for the archiveorg plugin
  */
-class PluginArchiveorgTest extends \PHPUnit\Framework\TestCase
+class PluginArchiveorgTest extends TestCase
 {
+    protected $savedScriptName;
+
     /**
      * Reset plugin path
      */
-    public function setUp()
+    public function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
+
+        // plugins manipulate global vars
+        $_SERVER['SERVER_PORT'] = '80';
+        $_SERVER['SERVER_NAME'] = 'shaarli.shaarli';
+        $this->savedScriptName = $_SERVER['SCRIPT_NAME'] ?? null;
+        $_SERVER['SCRIPT_NAME'] = '/index.php';
+    }
+
+    public function tearDown(): void
+    {
+        unset($_SERVER['SERVER_PORT']);
+        unset($_SERVER['SERVER_NAME']);
+        $_SERVER['SCRIPT_NAME'] = $this->savedScriptName;
     }
 
     /**
      * Test render_linklist hook on external bookmarks.
      */
-    public function testArchiveorgLinklistOnExternalLinks()
+    public function testArchiveorgLinklistOnExternalLinks(): void
     {
         $str = 'http://randomstr.com/test';
 
@@ -56,16 +73,16 @@ class PluginArchiveorgTest extends \PHPUnit\Framework\TestCase
     /**
      * Test render_linklist hook on internal bookmarks.
      */
-    public function testArchiveorgLinklistOnInternalLinks()
+    public function testArchiveorgLinklistOnInternalLinks(): void
     {
-        $internalLink1 = 'http://shaarli.shaarli/?qvMAqg';
-        $internalLinkRealURL1 = '?qvMAqg';
+        $internalLink1 = 'http://shaarli.shaarli/shaare/qvMAqg';
+        $internalLinkRealURL1 = '/shaare/qvMAqg';
 
-        $internalLink2 = 'http://shaarli.shaarli/?2_7zww';
-        $internalLinkRealURL2 = '?2_7zww';
+        $internalLink2 = 'http://shaarli.shaarli/shaare/2_7zww';
+        $internalLinkRealURL2 = '/shaare/2_7zww';
 
-        $internalLink3 = 'http://shaarli.shaarli/?z7u-_Q';
-        $internalLinkRealURL3 = '?z7u-_Q';
+        $internalLink3 = 'http://shaarli.shaarli/shaare/z7u-_Q';
+        $internalLinkRealURL3 = '/shaare/z7u-_Q';
 
         $data = array(
             'title' => $internalLink1,
index 9835dfa39ac7de4706d0f62b63cf86ed35f9d974..cc844c60f41e34edc0b61665e97c6f1227d6b3ac 100644 (file)
@@ -2,10 +2,10 @@
 
 namespace Shaarli\Plugin\DefaultColors;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\LinkDB;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
+use Shaarli\TestCase;
 
 require_once 'plugins/default_colors/default_colors.php';
 
@@ -19,7 +19,7 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'sandbox';
         mkdir(PluginManager::$PLUGINS_PATH . '/default_colors/');
@@ -32,7 +32,7 @@ class PluginDefaultColorsTest extends TestCase
     /**
      * Remove sandbox files and folder
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         if (file_exists('sandbox/default_colors/default_colors.css.template')) {
             unlink('sandbox/default_colors/default_colors.css.template');
index 994772051086ae03ebe1602ec0e39cf246f42cdc..16ecf357abce0307188db19771a32981bd0682a8 100644 (file)
@@ -5,6 +5,7 @@ use DateTime;
 use Shaarli\Bookmark\Bookmark;
 use Shaarli\Config\ConfigManager;
 use Shaarli\Plugin\PluginManager;
+use Shaarli\TestCase;
 
 require_once 'plugins/isso/isso.php';
 
@@ -13,12 +14,12 @@ require_once 'plugins/isso/isso.php';
  *
  * Test the Isso plugin (comment system).
  */
-class PluginIssoTest extends \PHPUnit\Framework\TestCase
+class PluginIssoTest extends TestCase
 {
     /**
      * Reset plugin path
      */
-    public function setUp()
+    public function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
@@ -26,7 +27,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test Isso init without errors.
      */
-    public function testIssoInitNoError()
+    public function testIssoInitNoError(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -37,7 +38,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test Isso init with errors.
      */
-    public function testIssoInitError()
+    public function testIssoInitError(): void
     {
         $conf = new ConfigManager('');
         $errors = isso_init($conf);
@@ -47,7 +48,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test render_linklist hook with valid settings to display the comment form.
      */
-    public function testIssoDisplayed()
+    public function testIssoDisplayed(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -87,7 +88,7 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
     /**
      * Test isso plugin when multiple bookmarks are displayed (shouldn't be displayed).
      */
-    public function testIssoMultipleLinks()
+    public function testIssoMultipleLinks(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -115,14 +116,14 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
 
         $processed = hook_isso_render_linklist($data, $conf);
         // link_plugin should be added for the icon
-        $this->assertContains('<a href="?'. $short1 .'#isso-thread">', $processed['links'][0]['link_plugin'][0]);
-        $this->assertContains('<a href="?'. $short2 .'#isso-thread">', $processed['links'][1]['link_plugin'][0]);
+        $this->assertContainsPolyfill('<a href="/shaare/'. $short1 .'#isso-thread">', $processed['links'][0]['link_plugin'][0]);
+        $this->assertContainsPolyfill('<a href="/shaare/'. $short2 .'#isso-thread">', $processed['links'][1]['link_plugin'][0]);
     }
 
     /**
      * Test isso plugin when using search (shouldn't be displayed).
      */
-    public function testIssoNotDisplayedWhenSearch()
+    public function testIssoNotDisplayedWhenSearch(): void
     {
         $conf = new ConfigManager('');
         $conf->set('plugins.ISSO_SERVER', 'value');
@@ -145,13 +146,13 @@ class PluginIssoTest extends \PHPUnit\Framework\TestCase
         $processed = hook_isso_render_linklist($data, $conf);
 
         // link_plugin should be added for the icon
-        $this->assertContains('<a href="?'. $short1 .'#isso-thread">', $processed['links'][0]['link_plugin'][0]);
+        $this->assertContainsPolyfill('<a href="/shaare/'. $short1 .'#isso-thread">', $processed['links'][0]['link_plugin'][0]);
     }
 
     /**
      * Test isso plugin without server configuration (shouldn't be displayed).
      */
-    public function testIssoWithoutConf()
+    public function testIssoWithoutConf(): void
     {
         $data = 'abc';
         $conf = new ConfigManager('');
index b7b6ce53fee211132aeee26030b3c1ffadd3249a..338d2e351a2344969a8d30e906a54edaca0b43e9 100644 (file)
@@ -14,12 +14,12 @@ require_once 'plugins/playvideos/playvideos.php';
  * Class PluginPlayvideosTest
  * Unit test for the PlayVideos plugin
  */
-class PluginPlayvideosTest extends \PHPUnit\Framework\TestCase
+class PluginPlayvideosTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
index e66f484edcdb6928ec4213ae918c2ebff2b36323..d3f7b439c35955a64de558a7da69b65f022fc458 100644 (file)
@@ -11,7 +11,7 @@ require_once 'plugins/pubsubhubbub/pubsubhubbub.php';
  * Class PluginPubsubhubbubTest
  * Unit test for the pubsubhubbub plugin
  */
-class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase
+class PluginPubsubhubbubTest extends \Shaarli\TestCase
 {
     /**
      * @var string Config file path (without extension).
@@ -21,7 +21,7 @@ class PluginPubsubhubbubTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
index c9f8c733d40adcac140fc2bdb5fe8ab817123f6c..1d85fba60ce76f26588faaab28708f0a2c1fca34 100644 (file)
@@ -14,12 +14,12 @@ require_once 'plugins/qrcode/qrcode.php';
  * Class PluginQrcodeTest
  * Unit test for the QR-Code plugin
  */
-class PluginQrcodeTest extends \PHPUnit\Framework\TestCase
+class PluginQrcodeTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
index 797519210c63c5827da633d870e90de1b152d6c3..36317215976e4a5c38fe8bf721525b903d764d8d 100644 (file)
@@ -10,12 +10,12 @@ require_once 'plugins/wallabag/wallabag.php';
  * Class PluginWallabagTest
  * Unit test for the Wallabag plugin
  */
-class PluginWallabagTest extends \PHPUnit\Framework\TestCase
+class PluginWallabagTest extends \Shaarli\TestCase
 {
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         PluginManager::$PLUGINS_PATH = 'plugins';
     }
index a3cd90765676c36920a9a58d2b0140133950a54d..5ef3de1a109a9e3b871b9036078be48e4d3b87ee 100644 (file)
@@ -4,7 +4,7 @@ namespace Shaarli\Plugin\Wallabag;
 /**
  * Class WallabagInstanceTest
  */
-class WallabagInstanceTest extends \PHPUnit\Framework\TestCase
+class WallabagInstanceTest extends \Shaarli\TestCase
 {
     /**
      * @var string wallabag url.
@@ -14,7 +14,7 @@ class WallabagInstanceTest extends \PHPUnit\Framework\TestCase
     /**
      * Reset plugin path
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->instance = 'http://some.url';
     }
index ae5032dd36a5b19fc999c387c008ff781481c70c..03be4f4e8c997bd9eb875ad1f42a65bf4d294eb7 100644 (file)
@@ -13,6 +13,9 @@ function hook_test_random($data)
         $data[1] = 'page test';
     } elseif (isset($data['_LOGGEDIN_']) && $data['_LOGGEDIN_'] === true) {
         $data[1] = 'loggedin';
+    } elseif (array_key_exists('_LOGGEDIN_', $data)) {
+        $data[1] = 'loggedin';
+        $data[2] = $data['_LOGGEDIN_'];
     } else {
         $data[1] = $data[0];
     }
index c258f45f566cb12a321730fa6a9f71e112648181..08d4e5ea0bd9f7b8b37e907fc4b8a90f7c96d3e4 100644 (file)
@@ -6,8 +6,8 @@
 
 namespace Shaarli\Render;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\Security\SessionManager;
+use Shaarli\TestCase;
 
 /**
  * Unitary tests for cached pages
@@ -29,7 +29,7 @@ class PageCacheManagerTest extends TestCase
     /**
      * Populate the cache with dummy files
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->cacheManager = new PageCacheManager(static::$testCacheDir, true);
 
@@ -48,7 +48,7 @@ class PageCacheManagerTest extends TestCase
     /**
      * Remove dummycache folder after each tests.
      */
-    public function tearDown()
+    protected function tearDown(): void
     {
         array_map('unlink', glob(self::$testCacheDir . '/*'));
         rmdir(self::$testCacheDir);
index 58e3426b2de3670ab40a2c12bc385c2b308652d8..7d841e4d4a2f31366a296b1e5c7da6c1057df5c5 100644 (file)
@@ -7,7 +7,7 @@ namespace Shaarli\Render;
  *
  * @package Shaarli
  */
-class ThemeUtilsTest extends \PHPUnit\Framework\TestCase
+class ThemeUtilsTest extends \Shaarli\TestCase
 {
     /**
      * Test getThemes() with existing theme directories.
index bba7c8ad76594c359b440e7d3a28f04fcdb293a3..698d3d10bdeadedafa4bfe2d01cdd8272251f685 100644 (file)
@@ -3,8 +3,8 @@
 
 namespace Shaarli\Security;
 
-use PHPUnit\Framework\TestCase;
 use Shaarli\FileUtils;
+use Shaarli\TestCase;
 
 /**
  * Test coverage for BanManager
@@ -32,7 +32,7 @@ class BanManagerTest extends TestCase
     /**
      * Prepare or reset test resources
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists($this->banFile)) {
             unlink($this->banFile);
index f242be0919685d9d5231e1ae20b96309471a136f..d302983de2b013e8ec91e79e9c04eb62f59b75fb 100644 (file)
@@ -2,7 +2,7 @@
 
 namespace Shaarli\Security;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 /**
  * Test coverage for LoginManager
@@ -63,7 +63,7 @@ class LoginManagerTest extends TestCase
     /**
      * Prepare or reset test resources
      */
-    public function setUp()
+    protected function setUp(): void
     {
         if (file_exists($this->banFile)) {
             unlink($this->banFile);
index 11a59f9c6e06b846623f02d465206220b807f085..3f9c3ef59fd2138faeb95fe07b715890a0f09ab4 100644 (file)
@@ -2,7 +2,7 @@
 
 namespace Shaarli\Security;
 
-use PHPUnit\Framework\TestCase;
+use Shaarli\TestCase;
 
 /**
  * Test coverage for SessionManager
@@ -24,7 +24,7 @@ class SessionManagerTest extends TestCase
     /**
      * Assign reference data
      */
-    public static function setUpBeforeClass()
+    public static function setUpBeforeClass(): void
     {
         self::$sidHashes = \ReferenceSessionIdHashes::getHashes();
     }
@@ -32,7 +32,7 @@ class SessionManagerTest extends TestCase
     /**
      * Initialize or reset test resources
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->conf = new \FakeConfigManager([
             'credentials.login' => 'johndoe',
index 07c7f5c48efd4b54ad35aff320a3b75b134038a6..3403233febf6d904ccefa817cb4719e5375a0ffa 100644 (file)
@@ -37,7 +37,7 @@ class DummyUpdater extends Updater
      *
      * @return bool true.
      */
-    final private function updateMethodDummy1()
+    final protected function updateMethodDummy1()
     {
         return true;
     }
@@ -47,7 +47,7 @@ class DummyUpdater extends Updater
      *
      * @return bool true.
      */
-    final private function updateMethodDummy2()
+    final protected function updateMethodDummy2()
     {
         return true;
     }
@@ -57,7 +57,7 @@ class DummyUpdater extends Updater
      *
      * @return bool true.
      */
-    final private function updateMethodDummy3()
+    final protected function updateMethodDummy3()
     {
         return true;
     }
@@ -67,7 +67,7 @@ class DummyUpdater extends Updater
      *
      * @throws Exception error.
      */
-    final private function updateMethodException()
+    final protected function updateMethodException()
     {
         throw new Exception('whatever');
     }
index a7dd70bfc4b1a386bf27b7d8964984a458e23607..a6280b8c9b911a8d3b33ac0d4af2684304a49256 100644 (file)
@@ -2,11 +2,11 @@
 namespace Shaarli\Updater;
 
 use Exception;
-use PHPUnit\Framework\TestCase;
 use Shaarli\Bookmark\BookmarkFileService;
 use Shaarli\Bookmark\BookmarkServiceInterface;
 use Shaarli\Config\ConfigManager;
 use Shaarli\History;
+use Shaarli\TestCase;
 
 
 /**
@@ -42,7 +42,7 @@ class UpdaterTest extends TestCase
     /**
      * Executed before each test.
      */
-    public function setUp()
+    protected function setUp(): void
     {
         $this->refDB = new \ReferenceLinkDB();
         $this->refDB->write(self::$testDatastore);
@@ -87,23 +87,23 @@ class UpdaterTest extends TestCase
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): empty updates file.
-     *
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Updates file path is not set(.*)/
      */
     public function testWriteEmptyUpdatesFile()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Updates file path is not set(.*)/');
+
         UpdaterUtils::write_updates_file('', array('test'));
     }
 
     /**
      * Test errors in UpdaterUtils::write_updates_file(): not writable updates file.
-     *
-     * @expectedException              Exception
-     * @expectedExceptionMessageRegExp /Unable to write(.*)/
      */
     public function testWriteUpdatesFileNotWritable()
     {
+        $this->expectException(\Exception::class);
+        $this->expectExceptionMessageRegExp('/Unable to write(.*)/');
+
         $updatesFile = $this->conf->get('resource.data_dir') . '/updates.txt';
         touch($updatesFile);
         chmod($updatesFile, 0444);
@@ -168,11 +168,11 @@ class UpdaterTest extends TestCase
 
     /**
      * Test Update failed.
-     *
-     * @expectedException \Exception
      */
     public function testUpdateFailed()
     {
+        $this->expectException(\Exception::class);
+
         $updates = array(
             'updateMethodDummy1',
             'updateMethodDummy2',
index 227f9b52ae805080ec089ff59b1d2e16d0ee0dfd..09768ac47905908bc5cbc274e230a407541bd946 100644 (file)
@@ -8,7 +8,7 @@
 <link href="{$asset_path}/img/favicon.png#" rel="shortcut icon" type="image/png" />
 <link href="{$asset_path}/img/apple-touch-icon.png#" rel="apple-touch-icon" sizes="180x180" />
 <link type="text/css" rel="stylesheet" href="{$asset_path}/css/shaarli.min.css?v={$version_hash}#" />
-{if="$formatter==='markdown'"}
+{if="strpos($formatter, 'markdown') !== false"}
   <link type="text/css" rel="stylesheet" href="{$asset_path}/css/markdown.min.css?v={$version_hash}#" />
 {/if}
 {loop="$plugins_includes.css_files"}
index 2475f5fdbe2eacf9db05b170534a4a4e44892ecb..b08773d8576162861561f359710d89346a69d509 100644 (file)
@@ -94,7 +94,7 @@
           {'tagged'|t}
           {loop="$exploded_tags"}
               <span class="label label-tag" title="{'Remove tag'|t}">
-                <a href="{$base_path}/remove-tag/{function="urlencode($value)"}" aria-label="{'Remove tag'|t}">
+                <a href="{$base_path}/remove-tag/{function="$search_tags_url.$key1"}" aria-label="{'Remove tag'|t}">
                   {$value}<span class="remove"><i class="fa fa-times" aria-hidden="true"></i></span>
                 </a>
               </span>
                 {$tag_counter=count($value.taglist)}
                 {loop="value.taglist"}
                   <span class="label label-tag" title="{$strAddTag}">
-                    <a href="{$base_path}/add-tag/{$value|urlencode}">{$value}</a>
+                    <a href="{$base_path}/add-tag/{$value1.urlencoded_taglist.$key2}">{$value}</a>
                   </span>
                   {if="$tag_counter - 1 != $counter"}&middot;{/if}
                 {/loop}
index 024882ec723db3310b145466f750a1eb1269a4d4..c067e1d459ed76dc232cc8e5f706e1f9a897306f 100644 (file)
@@ -15,7 +15,7 @@
     <h2 class="window-title">{'Tag cloud'|t} - {$countTags} {'tags'|t}</h2>
     {if="!empty($search_tags)"}
     <p class="center">
-      <a href="{$base_path}/?searchtags={$search_tags|urlencode}" class="pure-button pure-button-shaarli">
+      <a href="{$base_path}/?searchtags={$search_tags_url}" class="pure-button pure-button-shaarli">
         {'List all links with those tags'|t}
       </a>
     </p>
@@ -48,8 +48,8 @@
 
     <div id="cloudtag" class="cloudtag-container">
       {loop="tags"}
-        <a href="{$base_path}/?searchtags={$key|urlencode} {$search_tags|urlencode}" style="font-size:{$value.size}em;">{$key}</a
-        ><a href="{$base_path}/add-tag/{$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
+        <a href="{$base_path}/?searchtags={$tags_url.$key1} {$search_tags_url}" style="font-size:{$value.size}em;">{$key}</a
+        ><a href="{$base_path}/add-tag/{$tags_url.$key1}" title="{'Filter by tag'|t}" class="count">{$value.count}</a>
         {loop="$value.tag_plugin"}
           {$value}
         {/loop}
index 99ae44d2487f22a4a339a018968ce883c79b8ed2..96e7fbe0da8c752779e35fb7af29a6b6f45b0d58 100644 (file)
@@ -15,7 +15,7 @@
     <h2 class="window-title">{'Tag list'|t} - {$countTags} {'tags'|t}</h2>
     {if="!empty($search_tags)"}
       <p class="center">
-        <a href="{$base_path}/?searchtags={$search_tags|urlencode}" class="pure-button pure-button-shaarli">
+        <a href="{$base_path}/?searchtags={$search_tags_url}" class="pure-button pure-button-shaarli">
           {'List all links with those tags'|t}
         </a>
       </p>
 
     <div id="taglist" class="taglist-container">
       {loop="tags"}
-        <div class="tag-list-item pure-g" data-tag="{$key}">
+        <div class="tag-list-item pure-g" data-tag="{$key}" data-tag-url="{$tags_url.$key1}">
           <div class="pure-u-1">
             {if="$is_logged_in===true"}
               <a href="#" class="delete-tag" aria-label="{'Delete'|t}"><i class="fa fa-trash" aria-hidden="true"></i></a>&nbsp;&nbsp;
-              <a href="{$base_path}/admin/tags?fromtag={$key|urlencode}" class="rename-tag" aria-label="{'Rename tag'|t}">
+              <a href="{$base_path}/admin/tags?fromtag={$tags_url.$key1}" class="rename-tag" aria-label="{'Rename tag'|t}">
                 <i class="fa fa-pencil-square-o {$key}" aria-hidden="true"></i>
               </a>
             {/if}
 
-            <a href="{$base_path}/add-tag/{$key|urlencode}" title="{'Filter by tag'|t}" class="count">{$value}</a>
-            <a href="{$base_path}/?searchtags={$key|urlencode} {$search_tags|urlencode}" class="tag-link">{$key}</a>
+            <a href="{$base_path}/add-tag/{$tags_url.$key1}" title="{'Filter by tag'|t}" class="count">{$value}</a>
+            <a href="{$base_path}/?searchtags={$tags_url.$key1} {$search_tags_url}" class="tag-link">{$key}</a>
 
             {loop="$value.tag_plugin"}
               {$value}
index 8718b188370c6008f5edd77334378242a4b92b3b..b3764e290082ae26e5b9b8c0ccc16f6e7759f414 100644 (file)
@@ -1,8 +1,8 @@
 <div class="pure-g">
   <div class="pure-u-1 pure-alert pure-alert-success tag-sort">
     {'Sort by:'|t}
-    <a href="{$base_path}/tags/cloud">{'Cloud'|t}</a> &middot;
-    <a href="{$base_path}/tags/list?sort=usage">{'Most used'|t}</a> &middot;
+    <a href="{$base_path}/tags/cloud">{'Cloud'|t}</a>
+    <a href="{$base_path}/tags/list?sort=usage">{'Most used'|t}</a>
     <a href="{$base_path}/tags/list?sort=alpha">{'Alphabetical'|t}</a>
   </div>
 </div>
index c3671b1f960bf8b2432f13920bc941c63af828a4..eb8807b5a2d0fc7bdbc594f0a020815f3e331834 100644 (file)
@@ -11,7 +11,6 @@
     <div id="shaarli_title"><a href="{$titleLink}">{$shaarlititle}</a></div>
     <div id="editlinkform">
         <form method="post" name="linkform" action="{$base_path}/admin/shaare">
-            <input type="hidden" name="lf_linkdate" value="{$link.linkdate}">
           {if="isset($link.id)"}
                  <input type="hidden" name="lf_id" value="{$link.id}">
           {/if}
index b9396df6de74d61f8f19a5e6d67a01bb6e169fb1..79daf16c26c5273090c517b68b2b5504fa628f5d 100644 (file)
@@ -32,6 +32,6 @@
         </form>
     </div>
     {if="$previous_page_url"} <a href="{$previous_page_url}" class="paging_older">&#x25C4;Older</a> {/if}
-    <div class="paging_current">page {$page_current} / {$page_max} </div>
+    {if="$page_max>1"}<div class="paging_current">page {$page_current} / {$page_max} </div>{/if}
     {if="$next_page_url"} <a href="{$next_page_url}" class="paging_newer">Newer&#x25BA;</a> {/if}
 </div>
index 602147e51d3d200b8dcf45bbb6df7f951e08c6c3..a73758cce4af906044e9ed9f1ae31fa8941993e1 100644 (file)
@@ -2,26 +2,21 @@ const path = require('path');
 const glob = require('glob');
 
 // Minify JS
-const MinifyPlugin = require('babel-minify-webpack-plugin');
+const TerserPlugin = require('terser-webpack-plugin');
 
 // This plugin extracts the CSS into its own file instead of tying it with the JS.
 // It prevents:
 //   - not having styles due to a JS error
 //   - the flash page without styles during JS loading
-const ExtractTextPlugin = require("extract-text-webpack-plugin");
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
 
-const extractCssDefault = new ExtractTextPlugin({
+const extractCss = new MiniCssExtractPlugin({
   filename: "../css/[name].min.css",
-  publicPath: 'tpl/default/css/',
-});
-
-const extractCssVintage = new ExtractTextPlugin({
-  filename: "../css/[name].min.css",
-  publicPath: 'tpl/vintage/css/',
 });
 
 module.exports = [
   {
+    mode: 'production',
     entry: {
       thumbnails: './assets/common/js/thumbnails.js',
       thumbnails_update: './assets/common/js/thumbnails-update.js',
@@ -45,23 +40,23 @@ module.exports = [
             loader: 'babel-loader',
             options: {
               presets: [
-                'babel-preset-env',
+                '@babel/preset-env',
               ]
             }
           }
         },
         {
           test: /\.s?css/,
-          use: extractCssDefault.extract({
-            use: [{
-              loader: "css-loader",
+          use: [
+            {
+              loader: MiniCssExtractPlugin.loader,
               options: {
-                minimize: true,
-              }
-            }, {
-              loader: "sass-loader"
-            }],
-          })
+                publicPath: 'tpl/default/css/',
+              },
+            },
+            'css-loader',
+            'sass-loader',
+          ],
         },
         {
           test: /\.(gif|png|jpe?g|svg|ico)$/i,
@@ -81,17 +76,21 @@ module.exports = [
           options: {
             name: '../fonts/[name].[ext]',
             // do not add a publicPath here because it's already handled by CSS's publicPath
-            publicPath: '',
+            publicPath: '../default/',
           }
         },
       ],
     },
+    optimization: {
+      minimize: true,
+      minimizer: [new TerserPlugin()],
+    },
     plugins: [
-      new MinifyPlugin(),
-      extractCssDefault,
+      extractCss,
     ],
   },
   {
+    mode: 'production',
     entry: {
       shaarli: [
         './assets/vintage/js/base.js',
@@ -115,21 +114,23 @@ module.exports = [
             loader: 'babel-loader',
             options: {
               presets: [
-                'babel-preset-env',
+                '@babel/preset-env',
               ]
             }
           }
         },
         {
           test: /\.css$/,
-          use: extractCssVintage.extract({
-            use: [{
-              loader: "css-loader",
+          use: [
+            {
+              loader: MiniCssExtractPlugin.loader,
               options: {
-                minimize: true,
-              }
-            }],
-          })
+                publicPath: 'tpl/vintage/css/',
+              },
+            },
+            'css-loader',
+            'sass-loader',
+          ],
         },
         {
           test: /\.(gif|png|jpe?g|svg|ico)$/i,
@@ -145,9 +146,12 @@ module.exports = [
         },
       ],
     },
+    optimization: {
+      minimize: true,
+      minimizer: [new TerserPlugin()],
+    },
     plugins: [
-      new MinifyPlugin(),
-      extractCssVintage,
+      extractCss,
     ],
   },
 ];
index df6479505770634460f8b5c5ddc6e12eba09f3af..0a12820c83b2a4a357ec95f8560a1ef9f47c713a 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
 # yarn lockfile v1
 
 
-abbrev@1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
-  integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a"
+  integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==
+  dependencies:
+    "@babel/highlight" "^7.10.4"
+
+"@babel/compat-data@^7.10.4", "@babel/compat-data@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.11.0.tgz#e9f73efe09af1355b723a7f39b11bad637d7c99c"
+  integrity sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==
+  dependencies:
+    browserslist "^4.12.0"
+    invariant "^2.2.4"
+    semver "^5.5.0"
+
+"@babel/core@>=7.9.0", "@babel/core@^7.11.6":
+  version "7.11.6"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.11.6.tgz#3a9455dc7387ff1bac45770650bc13ba04a15651"
+  integrity sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/generator" "^7.11.6"
+    "@babel/helper-module-transforms" "^7.11.0"
+    "@babel/helpers" "^7.10.4"
+    "@babel/parser" "^7.11.5"
+    "@babel/template" "^7.10.4"
+    "@babel/traverse" "^7.11.5"
+    "@babel/types" "^7.11.5"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.1"
+    json5 "^2.1.2"
+    lodash "^4.17.19"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/generator@^7.11.5", "@babel/generator@^7.11.6":
+  version "7.11.6"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.11.6.tgz#b868900f81b163b4d464ea24545c61cbac4dc620"
+  integrity sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==
+  dependencies:
+    "@babel/types" "^7.11.5"
+    jsesc "^2.5.1"
+    source-map "^0.5.0"
+
+"@babel/helper-annotate-as-pure@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3"
+  integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3"
+  integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==
+  dependencies:
+    "@babel/helper-explode-assignable-expression" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-compilation-targets@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz#804ae8e3f04376607cc791b9d47d540276332bd2"
+  integrity sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==
+  dependencies:
+    "@babel/compat-data" "^7.10.4"
+    browserslist "^4.12.0"
+    invariant "^2.2.4"
+    levenary "^1.1.1"
+    semver "^5.5.0"
+
+"@babel/helper-create-class-features-plugin@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz#9f61446ba80e8240b0a5c85c6fdac8459d6f259d"
+  integrity sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==
+  dependencies:
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/helper-member-expression-to-functions" "^7.10.5"
+    "@babel/helper-optimise-call-expression" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-replace-supers" "^7.10.4"
+    "@babel/helper-split-export-declaration" "^7.10.4"
+
+"@babel/helper-create-regexp-features-plugin@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz#fdd60d88524659a0b6959c0579925e425714f3b8"
+  integrity sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/helper-regex" "^7.10.4"
+    regexpu-core "^4.7.0"
+
+"@babel/helper-define-map@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30"
+  integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/types" "^7.10.5"
+    lodash "^4.17.19"
+
+"@babel/helper-explode-assignable-expression@^7.10.4":
+  version "7.11.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz#2d8e3470252cc17aba917ede7803d4a7a276a41b"
+  integrity sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-function-name@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a"
+  integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.10.4"
+    "@babel/template" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-get-function-arity@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2"
+  integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-hoist-variables@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e"
+  integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-member-expression-to-functions@^7.10.4", "@babel/helper-member-expression-to-functions@^7.10.5":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz#ae69c83d84ee82f4b42f96e2a09410935a8f26df"
+  integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==
+  dependencies:
+    "@babel/types" "^7.11.0"
+
+"@babel/helper-module-imports@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
+  integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz#b16f250229e47211abdd84b34b64737c2ab2d359"
+  integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==
+  dependencies:
+    "@babel/helper-module-imports" "^7.10.4"
+    "@babel/helper-replace-supers" "^7.10.4"
+    "@babel/helper-simple-access" "^7.10.4"
+    "@babel/helper-split-export-declaration" "^7.11.0"
+    "@babel/template" "^7.10.4"
+    "@babel/types" "^7.11.0"
+    lodash "^4.17.19"
+
+"@babel/helper-optimise-call-expression@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673"
+  integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==
+  dependencies:
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375"
+  integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==
+
+"@babel/helper-regex@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0"
+  integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==
+  dependencies:
+    lodash "^4.17.19"
+
+"@babel/helper-remap-async-to-generator@^7.10.4":
+  version "7.11.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz#4474ea9f7438f18575e30b0cac784045b402a12d"
+  integrity sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/helper-wrap-function" "^7.10.4"
+    "@babel/template" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-replace-supers@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz#d585cd9388ea06e6031e4cd44b6713cbead9e6cf"
+  integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.10.4"
+    "@babel/helper-optimise-call-expression" "^7.10.4"
+    "@babel/traverse" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-simple-access@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz#0f5ccda2945277a2a7a2d3a821e15395edcf3461"
+  integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==
+  dependencies:
+    "@babel/template" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helper-skip-transparent-expression-wrappers@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz#eec162f112c2f58d3af0af125e3bb57665146729"
+  integrity sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==
+  dependencies:
+    "@babel/types" "^7.11.0"
+
+"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f"
+  integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==
+  dependencies:
+    "@babel/types" "^7.11.0"
+
+"@babel/helper-validator-identifier@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
+  integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
+
+"@babel/helper-wrap-function@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87"
+  integrity sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==
+  dependencies:
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/template" "^7.10.4"
+    "@babel/traverse" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/helpers@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.4.tgz#2abeb0d721aff7c0a97376b9e1f6f65d7a475044"
+  integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==
+  dependencies:
+    "@babel/template" "^7.10.4"
+    "@babel/traverse" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/highlight@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
+  integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.10.4"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.10.4", "@babel/parser@^7.11.5":
+  version "7.11.5"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037"
+  integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==
 
-acorn-dynamic-import@^2.0.0:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4"
-  integrity sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=
+"@babel/plugin-proposal-async-generator-functions@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz#3491cabf2f7c179ab820606cec27fed15e0e8558"
+  integrity sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-remap-async-to-generator" "^7.10.4"
+    "@babel/plugin-syntax-async-generators" "^7.8.0"
+
+"@babel/plugin-proposal-class-properties@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz#a33bf632da390a59c7a8c570045d1115cd778807"
+  integrity sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==
   dependencies:
-    acorn "^4.0.3"
-
-acorn-jsx@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
-  integrity sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=
+    "@babel/helper-create-class-features-plugin" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-proposal-dynamic-import@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz#ba57a26cb98b37741e9d5bca1b8b0ddf8291f17e"
+  integrity sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+
+"@babel/plugin-proposal-export-namespace-from@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz#570d883b91031637b3e2958eea3c438e62c05f54"
+  integrity sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==
   dependencies:
-    acorn "^3.0.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
 
-acorn@^3.0.4:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
-  integrity sha1-ReN/s56No/JbruP/U2niu18iAXo=
+"@babel/plugin-proposal-json-strings@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz#593e59c63528160233bd321b1aebe0820c2341db"
+  integrity sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-json-strings" "^7.8.0"
 
-acorn@^4.0.3:
-  version "4.0.13"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
-  integrity sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=
+"@babel/plugin-proposal-logical-assignment-operators@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz#9f80e482c03083c87125dee10026b58527ea20c8"
+  integrity sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
 
-acorn@^5.0.0, acorn@^5.5.0:
-  version "5.7.3"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
-  integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz#02a7e961fc32e6d5b2db0649e01bf80ddee7e04a"
+  integrity sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
 
-ajv-keywords@^1.0.0:
-  version "1.5.1"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
-  integrity sha1-MU3QpLM2j609/NxU7eYXG4htrzw=
+"@babel/plugin-proposal-numeric-separator@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz#ce1590ff0a65ad12970a609d78855e9a4c1aef06"
+  integrity sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-numeric-separator" "^7.10.4"
 
-ajv-keywords@^2.1.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
-  integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=
+"@babel/plugin-proposal-object-rest-spread@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz#bd81f95a1f746760ea43b6c2d3d62b11790ad0af"
+  integrity sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+    "@babel/plugin-transform-parameters" "^7.10.4"
 
-ajv-keywords@^3.1.0:
-  version "3.4.0"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.0.tgz#4b831e7b531415a7cc518cd404e73f6193c6349d"
-  integrity sha512-aUjdRFISbuFOl0EIZc+9e4FfZp0bDZgAdOOf30bJmw8VM9v84SHyVyxDfbWxpGYbdZD/9XoKxfHVNmxPkhwyGw==
+"@babel/plugin-proposal-optional-catch-binding@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz#31c938309d24a78a49d68fdabffaa863758554dd"
+  integrity sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
 
-ajv@^4.7.0:
-  version "4.11.8"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536"
-  integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=
+"@babel/plugin-proposal-optional-chaining@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz#de5866d0646f6afdaab8a566382fe3a221755076"
+  integrity sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==
   dependencies:
-    co "^4.6.0"
-    json-stable-stringify "^1.0.1"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0"
+    "@babel/plugin-syntax-optional-chaining" "^7.8.0"
 
-ajv@^5.0.0, ajv@^5.2.3, ajv@^5.3.0:
-  version "5.5.2"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
-  integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=
+"@babel/plugin-proposal-private-methods@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz#b160d972b8fdba5c7d111a145fc8c421fc2a6909"
+  integrity sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==
   dependencies:
-    co "^4.6.0"
-    fast-deep-equal "^1.0.0"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.3.0"
+    "@babel/helper-create-class-features-plugin" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-ajv@^6.1.0, ajv@^6.5.5:
-  version "6.10.0"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
-  integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
+"@babel/plugin-proposal-unicode-property-regex@^7.10.4", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz#4483cda53041ce3413b7fe2f00022665ddfaa75d"
+  integrity sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==
   dependencies:
-    fast-deep-equal "^2.0.1"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.4.1"
-    uri-js "^4.2.2"
+    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-align-text@^0.1.1, align-text@^0.1.3:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
-  integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
+"@babel/plugin-syntax-async-generators@^7.8.0":
+  version "7.8.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+  integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
   dependencies:
-    kind-of "^3.0.2"
-    longest "^1.0.1"
-    repeat-string "^1.5.2"
+    "@babel/helper-plugin-utils" "^7.8.0"
 
-alphanum-sort@^1.0.1, alphanum-sort@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
-  integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=
+"@babel/plugin-syntax-class-properties@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz#6644e6a0baa55a61f9e3231f6c9eeb6ee46c124c"
+  integrity sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-amdefine@>=0.0.4:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
-  integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
+"@babel/plugin-syntax-dynamic-import@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
+  integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
 
-ansi-escapes@^1.1.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
-  integrity sha1-06ioOzGapneTZisT52HHkRQiMG4=
+"@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"
 
-ansi-escapes@^3.0.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
-  integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+"@babel/plugin-syntax-json-strings@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
+  integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
 
-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=
+"@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"
 
-ansi-regex@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
-  integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
+  integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
 
-ansi-styles@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
-  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+"@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"
 
-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==
+"@babel/plugin-syntax-object-rest-spread@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+  integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
   dependencies:
-    color-convert "^1.9.0"
+    "@babel/helper-plugin-utils" "^7.8.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==
+"@babel/plugin-syntax-optional-catch-binding@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
+  integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
   dependencies:
-    micromatch "^3.1.4"
-    normalize-path "^2.1.1"
+    "@babel/helper-plugin-utils" "^7.8.0"
 
-aproba@^1.0.3:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
-  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+"@babel/plugin-syntax-optional-chaining@^7.8.0":
+  version "7.8.3"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
+  integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.8.0"
 
-are-we-there-yet@~1.1.2:
-  version "1.1.5"
-  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
-  integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+"@babel/plugin-syntax-top-level-await@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz#4bbeb8917b54fcf768364e0a81f560e33a3ef57d"
+  integrity sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==
   dependencies:
-    delegates "^1.0.0"
-    readable-stream "^2.0.6"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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==
+"@babel/plugin-transform-arrow-functions@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz#e22960d77e697c74f41c501d44d73dbf8a6a64cd"
+  integrity sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==
   dependencies:
-    sprintf-js "~1.0.2"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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=
+"@babel/plugin-transform-async-to-generator@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz#41a5017e49eb6f3cda9392a51eef29405b245a37"
+  integrity sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==
+  dependencies:
+    "@babel/helper-module-imports" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-remap-async-to-generator" "^7.10.4"
 
-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==
+"@babel/plugin-transform-block-scoped-functions@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz#1afa595744f75e43a91af73b0d998ecfe4ebc2e8"
+  integrity sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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=
+"@babel/plugin-transform-block-scoping@^7.10.4":
+  version "7.11.1"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz#5b7efe98852bef8d652c0b28144cd93a9e4b5215"
+  integrity sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-array-find-index@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
-  integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+"@babel/plugin-transform-classes@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz#405136af2b3e218bc4a1926228bc917ab1a0adc7"
+  integrity sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/helper-define-map" "^7.10.4"
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/helper-optimise-call-expression" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-replace-supers" "^7.10.4"
+    "@babel/helper-split-export-declaration" "^7.10.4"
+    globals "^11.1.0"
 
-array-includes@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d"
-  integrity sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=
+"@babel/plugin-transform-computed-properties@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz#9ded83a816e82ded28d52d4b4ecbdd810cdfc0eb"
+  integrity sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==
   dependencies:
-    define-properties "^1.1.2"
-    es-abstract "^1.7.0"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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=
+"@babel/plugin-transform-destructuring@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz#70ddd2b3d1bea83d01509e9bb25ddb3a74fc85e5"
+  integrity sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-asn1.js@^4.0.0:
-  version "4.10.1"
-  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
-  integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
+"@babel/plugin-transform-dotall-regex@^7.10.4", "@babel/plugin-transform-dotall-regex@^7.4.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz#469c2062105c1eb6a040eaf4fac4b488078395ee"
+  integrity sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==
   dependencies:
-    bn.js "^4.0.0"
-    inherits "^2.0.1"
-    minimalistic-assert "^1.0.0"
+    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-asn1@~0.2.3:
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
-  integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+"@babel/plugin-transform-duplicate-keys@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz#697e50c9fee14380fe843d1f306b295617431e47"
+  integrity sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==
   dependencies:
-    safer-buffer "~2.1.0"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-assert-plus@1.0.0, assert-plus@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
-  integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+"@babel/plugin-transform-exponentiation-operator@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz#5ae338c57f8cf4001bdb35607ae66b92d665af2e"
+  integrity sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==
+  dependencies:
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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==
+"@babel/plugin-transform-for-of@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz#c08892e8819d3a5db29031b115af511dbbfebae9"
+  integrity sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==
   dependencies:
-    object-assign "^4.1.1"
-    util "0.10.3"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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=
+"@babel/plugin-transform-function-name@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz#6a467880e0fc9638514ba369111811ddbe2644b7"
+  integrity sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==
+  dependencies:
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-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==
+"@babel/plugin-transform-literals@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz#9f42ba0841100a135f22712d0e391c462f571f3c"
+  integrity sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-async-foreach@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
-  integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
+"@babel/plugin-transform-member-expression-literals@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz#b1ec44fcf195afcb8db2c62cd8e551c881baf8b7"
+  integrity sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-async@^2.1.2, async@^2.4.1:
-  version "2.6.2"
-  resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
-  integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
+"@babel/plugin-transform-modules-amd@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz#1b9cddaf05d9e88b3aad339cb3e445c4f020a9b1"
+  integrity sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==
   dependencies:
-    lodash "^4.17.11"
+    "@babel/helper-module-transforms" "^7.10.5"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    babel-plugin-dynamic-import-node "^2.3.3"
 
-asynckit@^0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
-  integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+"@babel/plugin-transform-modules-commonjs@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz#66667c3eeda1ebf7896d41f1f16b17105a2fbca0"
+  integrity sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-simple-access" "^7.10.4"
+    babel-plugin-dynamic-import-node "^2.3.3"
 
-atob@^2.1.1:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
-  integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+"@babel/plugin-transform-modules-systemjs@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz#6270099c854066681bae9e05f87e1b9cadbe8c85"
+  integrity sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.10.4"
+    "@babel/helper-module-transforms" "^7.10.5"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    babel-plugin-dynamic-import-node "^2.3.3"
 
-autoprefixer@^6.3.1:
-  version "6.7.7"
-  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
-  integrity sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=
+"@babel/plugin-transform-modules-umd@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz#9a8481fe81b824654b3a0b65da3df89f3d21839e"
+  integrity sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==
   dependencies:
-    browserslist "^1.7.6"
-    caniuse-db "^1.0.30000634"
-    normalize-range "^0.1.2"
-    num2fraction "^1.2.2"
-    postcss "^5.2.16"
-    postcss-value-parser "^3.2.3"
+    "@babel/helper-module-transforms" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-awesomplete@^1.1.2:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/awesomplete/-/awesomplete-1.1.4.tgz#cdfcbbb2391857ff3a3340b5b1ebde7701b355e6"
-  integrity sha512-AgYrODNlVD3ZJ6Em54YesLnOSusuVCjoRAt0l5bi3L1Oiv5r5dkPdxVPJaG3/wnPlxRUmGcpGnK02VK7N02kCg==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz#78b4d978810b6f3bcf03f9e318f2fc0ed41aecb6"
+  integrity sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
 
-aws-sign2@~0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
-  integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+"@babel/plugin-transform-new-target@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz#9097d753cb7b024cb7381a3b2e52e9513a9c6888"
+  integrity sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
 
-aws4@^1.8.0:
-  version "1.8.0"
-  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
-  integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+"@babel/plugin-transform-object-super@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz#d7146c4d139433e7a6526f888c667e314a093894"
+  integrity sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-replace-supers" "^7.10.4"
+
+"@babel/plugin-transform-parameters@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz#59d339d58d0b1950435f4043e74e2510005e2c4a"
+  integrity sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-property-literals@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz#f6fe54b6590352298785b83edd815d214c42e3c0"
+  integrity sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-regenerator@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz#2015e59d839074e76838de2159db421966fd8b63"
+  integrity sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==
+  dependencies:
+    regenerator-transform "^0.14.2"
+
+"@babel/plugin-transform-reserved-words@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz#8f2682bcdcef9ed327e1b0861585d7013f8a54dd"
+  integrity sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-shorthand-properties@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz#9fd25ec5cdd555bb7f473e5e6ee1c971eede4dd6"
+  integrity sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-spread@^7.11.0":
+  version "7.11.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz#fa84d300f5e4f57752fe41a6d1b3c554f13f17cc"
+  integrity sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.11.0"
+
+"@babel/plugin-transform-sticky-regex@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz#8f3889ee8657581130a29d9cc91d7c73b7c4a28d"
+  integrity sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/helper-regex" "^7.10.4"
+
+"@babel/plugin-transform-template-literals@^7.10.4":
+  version "7.10.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz#78bc5d626a6642db3312d9d0f001f5e7639fde8c"
+  integrity sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-typeof-symbol@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz#9509f1a7eec31c4edbffe137c16cc33ff0bc5bfc"
+  integrity sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-unicode-escapes@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz#feae523391c7651ddac115dae0a9d06857892007"
+  integrity sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-transform-unicode-regex@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz#e56d71f9282fac6db09c82742055576d5e6d80a8"
+  integrity sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/preset-env@^7.11.5":
+  version "7.11.5"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.11.5.tgz#18cb4b9379e3e92ffea92c07471a99a2914e4272"
+  integrity sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA==
+  dependencies:
+    "@babel/compat-data" "^7.11.0"
+    "@babel/helper-compilation-targets" "^7.10.4"
+    "@babel/helper-module-imports" "^7.10.4"
+    "@babel/helper-plugin-utils" "^7.10.4"
+    "@babel/plugin-proposal-async-generator-functions" "^7.10.4"
+    "@babel/plugin-proposal-class-properties" "^7.10.4"
+    "@babel/plugin-proposal-dynamic-import" "^7.10.4"
+    "@babel/plugin-proposal-export-namespace-from" "^7.10.4"
+    "@babel/plugin-proposal-json-strings" "^7.10.4"
+    "@babel/plugin-proposal-logical-assignment-operators" "^7.11.0"
+    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.10.4"
+    "@babel/plugin-proposal-numeric-separator" "^7.10.4"
+    "@babel/plugin-proposal-object-rest-spread" "^7.11.0"
+    "@babel/plugin-proposal-optional-catch-binding" "^7.10.4"
+    "@babel/plugin-proposal-optional-chaining" "^7.11.0"
+    "@babel/plugin-proposal-private-methods" "^7.10.4"
+    "@babel/plugin-proposal-unicode-property-regex" "^7.10.4"
+    "@babel/plugin-syntax-async-generators" "^7.8.0"
+    "@babel/plugin-syntax-class-properties" "^7.10.4"
+    "@babel/plugin-syntax-dynamic-import" "^7.8.0"
+    "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+    "@babel/plugin-syntax-json-strings" "^7.8.0"
+    "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+    "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0"
+    "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+    "@babel/plugin-syntax-object-rest-spread" "^7.8.0"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.8.0"
+    "@babel/plugin-syntax-optional-chaining" "^7.8.0"
+    "@babel/plugin-syntax-top-level-await" "^7.10.4"
+    "@babel/plugin-transform-arrow-functions" "^7.10.4"
+    "@babel/plugin-transform-async-to-generator" "^7.10.4"
+    "@babel/plugin-transform-block-scoped-functions" "^7.10.4"
+    "@babel/plugin-transform-block-scoping" "^7.10.4"
+    "@babel/plugin-transform-classes" "^7.10.4"
+    "@babel/plugin-transform-computed-properties" "^7.10.4"
+    "@babel/plugin-transform-destructuring" "^7.10.4"
+    "@babel/plugin-transform-dotall-regex" "^7.10.4"
+    "@babel/plugin-transform-duplicate-keys" "^7.10.4"
+    "@babel/plugin-transform-exponentiation-operator" "^7.10.4"
+    "@babel/plugin-transform-for-of" "^7.10.4"
+    "@babel/plugin-transform-function-name" "^7.10.4"
+    "@babel/plugin-transform-literals" "^7.10.4"
+    "@babel/plugin-transform-member-expression-literals" "^7.10.4"
+    "@babel/plugin-transform-modules-amd" "^7.10.4"
+    "@babel/plugin-transform-modules-commonjs" "^7.10.4"
+    "@babel/plugin-transform-modules-systemjs" "^7.10.4"
+    "@babel/plugin-transform-modules-umd" "^7.10.4"
+    "@babel/plugin-transform-named-capturing-groups-regex" "^7.10.4"
+    "@babel/plugin-transform-new-target" "^7.10.4"
+    "@babel/plugin-transform-object-super" "^7.10.4"
+    "@babel/plugin-transform-parameters" "^7.10.4"
+    "@babel/plugin-transform-property-literals" "^7.10.4"
+    "@babel/plugin-transform-regenerator" "^7.10.4"
+    "@babel/plugin-transform-reserved-words" "^7.10.4"
+    "@babel/plugin-transform-shorthand-properties" "^7.10.4"
+    "@babel/plugin-transform-spread" "^7.11.0"
+    "@babel/plugin-transform-sticky-regex" "^7.10.4"
+    "@babel/plugin-transform-template-literals" "^7.10.4"
+    "@babel/plugin-transform-typeof-symbol" "^7.10.4"
+    "@babel/plugin-transform-unicode-escapes" "^7.10.4"
+    "@babel/plugin-transform-unicode-regex" "^7.10.4"
+    "@babel/preset-modules" "^0.1.3"
+    "@babel/types" "^7.11.5"
+    browserslist "^4.12.0"
+    core-js-compat "^3.6.2"
+    invariant "^2.2.2"
+    levenary "^1.1.1"
+    semver "^5.5.0"
 
-babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
-  integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=
+"@babel/preset-modules@^0.1.3":
+  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:
-    chalk "^1.1.3"
+    "@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"
-    js-tokens "^3.0.2"
-
-babel-core@^6.24.1, babel-core@^6.26.0:
-  version "6.26.3"
-  resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207"
-  integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==
-  dependencies:
-    babel-code-frame "^6.26.0"
-    babel-generator "^6.26.0"
-    babel-helpers "^6.24.1"
-    babel-messages "^6.23.0"
-    babel-register "^6.26.0"
-    babel-runtime "^6.26.0"
-    babel-template "^6.26.0"
-    babel-traverse "^6.26.0"
-    babel-types "^6.26.0"
-    babylon "^6.18.0"
-    convert-source-map "^1.5.1"
-    debug "^2.6.9"
-    json5 "^0.5.1"
-    lodash "^4.17.4"
+
+"@babel/runtime@^7.8.4":
+  version "7.11.2"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
+  integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
+"@babel/template@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278"
+  integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/parser" "^7.10.4"
+    "@babel/types" "^7.10.4"
+
+"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.5":
+  version "7.11.5"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.11.5.tgz#be777b93b518eb6d76ee2e1ea1d143daa11e61c3"
+  integrity sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/generator" "^7.11.5"
+    "@babel/helper-function-name" "^7.10.4"
+    "@babel/helper-split-export-declaration" "^7.11.0"
+    "@babel/parser" "^7.11.5"
+    "@babel/types" "^7.11.5"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.19"
+
+"@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.11.5", "@babel/types@^7.4.4":
+  version "7.11.5"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d"
+  integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.10.4"
+    lodash "^4.17.19"
+    to-fast-properties "^2.0.0"
+
+"@eslint/eslintrc@^0.1.3":
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085"
+  integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==
+  dependencies:
+    ajv "^6.12.4"
+    debug "^4.1.1"
+    espree "^7.3.0"
+    globals "^12.1.0"
+    ignore "^4.0.6"
+    import-fresh "^3.2.1"
+    js-yaml "^3.13.1"
+    lodash "^4.17.19"
     minimatch "^3.0.4"
-    path-is-absolute "^1.0.1"
-    private "^0.1.8"
-    slash "^1.0.0"
-    source-map "^0.5.7"
-
-babel-generator@^6.26.0:
-  version "6.26.1"
-  resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90"
-  integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==
-  dependencies:
-    babel-messages "^6.23.0"
-    babel-runtime "^6.26.0"
-    babel-types "^6.26.0"
-    detect-indent "^4.0.0"
-    jsesc "^1.3.0"
-    lodash "^4.17.4"
-    source-map "^0.5.7"
-    trim-right "^1.0.1"
-
-babel-helper-builder-binary-assignment-operator-visitor@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664"
-  integrity sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=
-  dependencies:
-    babel-helper-explode-assignable-expression "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-helper-call-delegate@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d"
-  integrity sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=
-  dependencies:
-    babel-helper-hoist-variables "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
-
-babel-helper-define-map@^6.24.1:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f"
-  integrity sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=
-  dependencies:
-    babel-helper-function-name "^6.24.1"
-    babel-runtime "^6.26.0"
-    babel-types "^6.26.0"
-    lodash "^4.17.4"
-
-babel-helper-evaluate-path@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz#0bb2eb01996c0cef53c5e8405e999fe4a0244c08"
-  integrity sha512-0EK9TUKMxHL549hWDPkQoS7R0Ozg1CDLheVBHYds2B2qoAvmr9ejY3zOXFsrICK73TN7bPhU14PBeKc8jcBTwg==
+    strip-json-comments "^3.1.1"
 
-babel-helper-explode-assignable-expression@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa"
-  integrity sha1-8luCz33BBDPFX3BZLVdGQArCLKo=
+"@nodelib/fs.scandir@2.1.3":
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
+  integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==
   dependencies:
-    babel-runtime "^6.22.0"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
+    "@nodelib/fs.stat" "2.0.3"
+    run-parallel "^1.1.9"
 
-babel-helper-flip-expressions@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz#160d2090a3d9f9c64a750905321a0bc218f884ec"
-  integrity sha512-rAsPA1pWBc7e2E6HepkP2e1sXugT+Oq/VCqhyuHJ8aJ2d/ifwnJfd4Qxjm21qlW43AN8tqaeByagKK6wECFMSw==
+"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3"
+  integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==
 
-babel-helper-function-name@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9"
-  integrity sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=
+"@nodelib/fs.walk@^1.2.3":
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976"
+  integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==
   dependencies:
-    babel-helper-get-function-arity "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
+    "@nodelib/fs.scandir" "2.1.3"
+    fastq "^1.6.0"
 
-babel-helper-get-function-arity@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d"
-  integrity sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=
+"@npmcli/move-file@^1.0.1":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464"
+  integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==
   dependencies:
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
+    mkdirp "^1.0.4"
 
-babel-helper-hoist-variables@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76"
-  integrity sha1-HssnaJydJVE+rbyZFKc/VAi+enY=
+"@stylelint/postcss-css-in-js@^0.37.2":
+  version "0.37.2"
+  resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.2.tgz#7e5a84ad181f4234a2480803422a47b8749af3d2"
+  integrity sha512-nEhsFoJurt8oUmieT8qy4nk81WRHmJynmVwn/Vts08PL9fhgIsMhk1GId5yAN643OzqEEb5S/6At2TZW7pqPDA==
   dependencies:
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
+    "@babel/core" ">=7.9.0"
 
-babel-helper-is-nodes-equiv@^0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz#34e9b300b1479ddd98ec77ea0bbe9342dfe39684"
-  integrity sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=
+"@stylelint/postcss-markdown@^0.36.1":
+  version "0.36.1"
+  resolved "https://registry.yarnpkg.com/@stylelint/postcss-markdown/-/postcss-markdown-0.36.1.tgz#829b87e6c0f108014533d9d7b987dc9efb6632e8"
+  integrity sha512-iDxMBWk9nB2BPi1VFQ+Dc5+XpvODBHw2n3tYpaBZuEAFQlbtF9If0Qh5LTTwSi/XwdbJ2jt+0dis3i8omyggpw==
+  dependencies:
+    remark "^12.0.0"
+    unist-util-find-all-after "^3.0.1"
 
-babel-helper-is-void-0@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz#6ed0ada8a9b1c5b6e88af6b47c1b3b5c080860eb"
-  integrity sha512-Axj1AYuD0E3Dl7nT3KxROP7VekEofz3XtEljzURf3fABalLpr8PamtgLFt+zuxtaCxRf9iuZmbAMMYWri5Bazw==
+"@types/color-name@^1.1.1":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
+  integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
 
-babel-helper-mark-eval-scopes@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz#7648aaf2ec92aae9b09a20ad91e8df5e1fcc94b2"
-  integrity sha512-KJuwrOUcHbvbh6he4xRXZFLaivK9DF9o3CrvpWnK1Wp0B+1ANYABXBMgwrnNFIDK/AvicxQ9CNr8wsgivlp4Aw==
-
-babel-helper-optimise-call-expression@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257"
-  integrity sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=
-  dependencies:
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-helper-regex@^6.24.1:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72"
-  integrity sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=
-  dependencies:
-    babel-runtime "^6.26.0"
-    babel-types "^6.26.0"
-    lodash "^4.17.4"
-
-babel-helper-remap-async-to-generator@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b"
-  integrity sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=
-  dependencies:
-    babel-helper-function-name "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
-
-babel-helper-remove-or-void@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz#8e46ad5b30560d57d7510b3fd93f332ee7c67386"
-  integrity sha512-1Z41upf/XR+PwY7Nd+F15Jo5BiQi5205ZXUuKed3yoyQgDkMyoM7vAdjEJS/T+M6jy32sXjskMUgms4zeiVtRA==
-
-babel-helper-replace-supers@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a"
-  integrity sha1-v22/5Dk40XNpohPKiov3S2qQqxo=
-  dependencies:
-    babel-helper-optimise-call-expression "^6.24.1"
-    babel-messages "^6.23.0"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
-
-babel-helper-to-multiple-sequence-expressions@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz#d1a419634c6cb301f27858c659167cfee0a9d318"
-  integrity sha512-ij9lpfdP3+Zc/7kNwa+NXbTrUlsYEWPwt/ugmQO0qflzLrveTIkbfOqQztvitk81aG5NblYDQXDlRohzu3oa8Q==
+"@types/json-schema@^7.0.5":
+  version "7.0.6"
+  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
+  integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
 
-babel-helpers@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2"
-  integrity sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=
-  dependencies:
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
+"@types/json5@^0.0.29":
+  version "0.0.29"
+  resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
+  integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
 
-babel-loader@^7.1.2:
-  version "7.1.5"
-  resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.5.tgz#e3ee0cd7394aa557e013b02d3e492bfd07aa6d68"
-  integrity sha512-iCHfbieL5d1LfOQeeVJEUyD9rTwBcP/fcEbRCfempxTDuqrKpu0AZjLAQHEQa3Yqyj9ORKe2iHfoj4rHLf7xpw==
-  dependencies:
-    find-cache-dir "^1.0.0"
-    loader-utils "^1.0.2"
-    mkdirp "^0.5.1"
+"@types/minimist@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
+  integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
 
-babel-messages@^6.23.0:
-  version "6.23.0"
-  resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e"
-  integrity sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=
-  dependencies:
-    babel-runtime "^6.22.0"
+"@types/node@*":
+  version "14.11.2"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.11.2.tgz#2de1ed6670439387da1c9f549a2ade2b0a799256"
+  integrity sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==
 
-babel-minify-webpack-plugin@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-minify-webpack-plugin/-/babel-minify-webpack-plugin-0.2.0.tgz#ef9694d11a1b8ab8f3204d89f5c9278dd28fc2a9"
-  integrity sha512-+5G5Qqm+DIVl7gY4rkHqlFRkaf1FZtz0imzu/Dy9+88AfOIuy7D5MQjkNgQr5gU6/YSZ+rImgxDqFcWkvvrjkQ==
-  dependencies:
-    babel-core "^6.24.1"
-    babel-preset-minify "^0.2.0"
-    webpack-sources "^1.0.1"
+"@types/normalize-package-data@^2.4.0":
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
+  integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
+
+"@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/unist@^2.0.0", "@types/unist@^2.0.2":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e"
+  integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==
+
+"@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==
+
+acorn-jsx@^5.2.0:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b"
+  integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==
+
+acorn@^6.4.1:
+  version "6.4.1"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
+  integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
+
+acorn@^7.4.0:
+  version "7.4.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c"
+  integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==
 
-babel-plugin-check-es2015-constants@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a"
-  integrity sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=
+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:
-    babel-runtime "^6.22.0"
+    clean-stack "^2.0.0"
+    indent-string "^4.0.0"
 
-babel-plugin-minify-builtins@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz#317f824b0907210b6348671bb040ca072e2e0c82"
-  integrity sha512-4i+8ntaS8gwVUcOz5y+zE+55OVOl2nTbmHV51D4wAIiKcRI8U5K//ip1GHfhsgk/NJrrHK7h97Oy5jpqt0Iixg==
+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.0, ajv@^6.10.2, ajv@^6.12.4:
+  version "6.12.5"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da"
+  integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==
   dependencies:
-    babel-helper-evaluate-path "^0.2.0"
+    fast-deep-equal "^3.1.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
 
-babel-plugin-minify-constant-folding@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz#8c70b528b2eb7c13e94d95c8789077d4cdbc3970"
-  integrity sha512-B3ffQBEUQ8ydlIkYv2MkZtTCbV7FAkWAV7NkyhcXlGpD10PaCxNGQ/B9oguXGowR1m16Q5nGhvNn8Pkn1MO6Hw==
+ansi-colors@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
+  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
+
+ansi-regex@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+  integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
+ansi-regex@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+  integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
+
+ansi-styles@^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:
-    babel-helper-evaluate-path "^0.2.0"
+    color-convert "^1.9.0"
 
-babel-plugin-minify-dead-code-elimination@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz#e8025ee10a1e5e4f202633a6928ce892c33747e3"
-  integrity sha512-zE7y3pRyzA4zK5nBou0kTcwUTSQ/AiFrynt1cIEYN7vcO2gS9ZFZoI0aO9JYLUdct5fsC1vfB35408yrzTyVfg==
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
+  integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
   dependencies:
-    babel-helper-evaluate-path "^0.2.0"
-    babel-helper-mark-eval-scopes "^0.2.0"
-    babel-helper-remove-or-void "^0.2.0"
-    lodash.some "^4.6.0"
+    "@types/color-name" "^1.1.1"
+    color-convert "^2.0.1"
 
-babel-plugin-minify-flip-comparisons@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz#0c9c8e93155c8f09dedad8118b634c259f709ef5"
-  integrity sha512-QOqXSEmD/LhT3LpM1WCyzAGcQZYYKJF7oOHvS6QbpomHenydrV53DMdPX2mK01icBExKZcJAHF209wvDBa+CSg==
+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:
-    babel-helper-is-void-0 "^0.2.0"
+    micromatch "^3.1.4"
+    normalize-path "^2.1.1"
 
-babel-plugin-minify-guarded-expressions@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz#8a8c950040fce3e258a12e6eb21eab94ad7235ab"
-  integrity sha512-5+NSPdRQ9mnrHaA+zFj+D5OzmSiv90EX5zGH6cWQgR/OUqmCHSDqgTRPFvOctgpo8MJyO7Rt7ajs2UfLnlAwYg==
+anymatch@~3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
+  integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
   dependencies:
-    babel-helper-flip-expressions "^0.2.0"
+    normalize-path "^3.0.0"
+    picomatch "^2.0.4"
 
-babel-plugin-minify-infinity@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz#30960c615ddbc657c045bb00a1d8eb4af257cf03"
-  integrity sha512-U694vrla1lN6vDHWGrR832t3a/A2eh+kyl019LxEE2+sS4VTydyOPRsAOIYAdJegWRA4cMX1lm9azAN0cLIr8g==
+aproba@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
 
-babel-plugin-minify-mangle-names@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz#719892297ff0106a6ec1a4b0fc062f1f8b6a8529"
-  integrity sha512-Gixuak1/CO7VCdjn15/8Bxe/QsAtDG4zPbnsNoe1mIJGCIH/kcmSjFhMlGJtXDQZd6EKzeMfA5WmX9+jvGRefw==
+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:
-    babel-helper-mark-eval-scopes "^0.2.0"
+    sprintf-js "~1.0.2"
 
-babel-plugin-minify-numeric-literals@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz#5746e851700167a380c05e93f289a7070459a0d1"
-  integrity sha512-VcLpb+r1YS7+RIOXdRsFVLLqoh22177USpHf+JM/g1nZbzdqENmfd5v534MLAbRErhbz6SyK+NQViVzVtBxu8g==
+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=
 
-babel-plugin-minify-replace@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz#3c1f06bc4e6d3e301eacb763edc1be611efc39b0"
-  integrity sha512-SEW6zoSVxh3OH6E1LCgyhhTWMnCv+JIRu5h5IlJDA11tU4ZeSF7uPQcO4vN/o52+FssRB26dmzJ/8D+z0QPg5Q==
+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==
 
-babel-plugin-minify-simplify@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz#21ceec4857100c5476d7cef121f351156e5c9bc0"
-  integrity sha512-Mj3Mwy2zVosMfXDWXZrQH5/uMAyfJdmDQ1NVqit+ArbHC3LlXVzptuyC1JxTyai/wgFvjLaichm/7vSUshkWqw==
+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-includes@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
+  integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==
   dependencies:
-    babel-helper-flip-expressions "^0.2.0"
-    babel-helper-is-nodes-equiv "^0.0.1"
-    babel-helper-to-multiple-sequence-expressions "^0.2.0"
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0"
+    is-string "^1.0.5"
 
-babel-plugin-minify-type-constructors@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz#7f3b6458be0863cfd59e9985bed6d134aa7a2e17"
-  integrity sha512-NiOvvA9Pq6bki6nP4BayXwT5GZadw7DJFDDzHmkpnOQpENWe8RtHtKZM44MG1R6EQ5XxgbLdsdhswIzTkFlO5g==
-  dependencies:
-    babel-helper-is-void-0 "^0.2.0"
-
-babel-plugin-syntax-async-functions@^6.8.0:
-  version "6.13.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
-  integrity sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=
-
-babel-plugin-syntax-exponentiation-operator@^6.8.0:
-  version "6.13.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
-  integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=
-
-babel-plugin-syntax-trailing-function-commas@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3"
-  integrity sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=
-
-babel-plugin-transform-async-to-generator@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761"
-  integrity sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=
-  dependencies:
-    babel-helper-remap-async-to-generator "^6.24.1"
-    babel-plugin-syntax-async-functions "^6.8.0"
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-arrow-functions@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221"
-  integrity sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141"
-  integrity sha1-u8UbSflk1wy42OC5ToICRs46YUE=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-block-scoping@^6.23.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f"
-  integrity sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=
-  dependencies:
-    babel-runtime "^6.26.0"
-    babel-template "^6.26.0"
-    babel-traverse "^6.26.0"
-    babel-types "^6.26.0"
-    lodash "^4.17.4"
-
-babel-plugin-transform-es2015-classes@^6.23.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db"
-  integrity sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=
-  dependencies:
-    babel-helper-define-map "^6.24.1"
-    babel-helper-function-name "^6.24.1"
-    babel-helper-optimise-call-expression "^6.24.1"
-    babel-helper-replace-supers "^6.24.1"
-    babel-messages "^6.23.0"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-es2015-computed-properties@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3"
-  integrity sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=
-  dependencies:
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-
-babel-plugin-transform-es2015-destructuring@^6.23.0:
-  version "6.23.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
-  integrity sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-duplicate-keys@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e"
-  integrity sha1-c+s9MQypaePvnskcU3QabxV2Qj4=
-  dependencies:
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-es2015-for-of@^6.23.0:
-  version "6.23.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
-  integrity sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-function-name@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b"
-  integrity sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=
-  dependencies:
-    babel-helper-function-name "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-es2015-literals@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e"
-  integrity sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154"
-  integrity sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=
-  dependencies:
-    babel-plugin-transform-es2015-modules-commonjs "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-
-babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1:
-  version "6.26.2"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3"
-  integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==
-  dependencies:
-    babel-plugin-transform-strict-mode "^6.24.1"
-    babel-runtime "^6.26.0"
-    babel-template "^6.26.0"
-    babel-types "^6.26.0"
-
-babel-plugin-transform-es2015-modules-systemjs@^6.23.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23"
-  integrity sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=
-  dependencies:
-    babel-helper-hoist-variables "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-
-babel-plugin-transform-es2015-modules-umd@^6.23.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468"
-  integrity sha1-rJl+YoXNGO1hdq22B9YCNErThGg=
-  dependencies:
-    babel-plugin-transform-es2015-modules-amd "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-
-babel-plugin-transform-es2015-object-super@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d"
-  integrity sha1-JM72muIcuDp/hgPa0CH1cusnj40=
-  dependencies:
-    babel-helper-replace-supers "^6.24.1"
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-parameters@^6.23.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b"
-  integrity sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=
-  dependencies:
-    babel-helper-call-delegate "^6.24.1"
-    babel-helper-get-function-arity "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-template "^6.24.1"
-    babel-traverse "^6.24.1"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-es2015-shorthand-properties@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0"
-  integrity sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=
-  dependencies:
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-es2015-spread@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1"
-  integrity sha1-1taKmfia7cRTbIGlQujdnxdG+NE=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-sticky-regex@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc"
-  integrity sha1-AMHNsaynERLN8M9hJsLta0V8zbw=
-  dependencies:
-    babel-helper-regex "^6.24.1"
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-es2015-template-literals@^6.22.0:
-  version "6.22.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d"
-  integrity sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
-  version "6.23.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
-  integrity sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=
-  dependencies:
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-es2015-unicode-regex@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9"
-  integrity sha1-04sS9C6nMj9yk4fxinxa4frrNek=
-  dependencies:
-    babel-helper-regex "^6.24.1"
-    babel-runtime "^6.22.0"
-    regexpu-core "^2.0.0"
-
-babel-plugin-transform-exponentiation-operator@^6.22.0:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e"
-  integrity sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=
-  dependencies:
-    babel-helper-builder-binary-assignment-operator-visitor "^6.24.1"
-    babel-plugin-syntax-exponentiation-operator "^6.8.0"
-    babel-runtime "^6.22.0"
-
-babel-plugin-transform-inline-consecutive-adds@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz#15dae78921057f4004f8eafd79e15ddc5f12f426"
-  integrity sha512-GlhOuLOQ28ua9prg0hT33HslCrEmz9xWXy9ZNZSACppCyRxxRW+haYtRgm7uYXCcd0q8ggCWD2pfWEJp5iiZfQ==
+array-union@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+  integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
 
-babel-plugin-transform-member-expression-literals@^6.8.5:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.9.4.tgz#37039c9a0c3313a39495faac2ff3a6b5b9d038bf"
-  integrity sha1-NwOcmgwzE6OUlfqsL/OmtbnQOL8=
+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=
 
-babel-plugin-transform-merge-sibling-variables@^6.8.6:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.9.4.tgz#85b422fc3377b449c9d1cde44087203532401dae"
-  integrity sha1-hbQi/DN3tEnJ0c3kQIcgNTJAHa4=
+array.prototype.flat@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
+  integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
 
-babel-plugin-transform-minify-booleans@^6.8.3:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.9.4.tgz#acbb3e56a3555dd23928e4b582d285162dd2b198"
-  integrity sha1-rLs+VqNVXdI5KOS1gtKFFi3SsZg=
+arrify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
+  integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
 
-babel-plugin-transform-property-literals@^6.8.5:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.9.4.tgz#98c1d21e255736573f93ece54459f6ce24985d39"
-  integrity sha1-mMHSHiVXNlc/k+zlRFn2ziSYXTk=
+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:
-    esutils "^2.0.2"
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    safer-buffer "^2.1.0"
 
-babel-plugin-transform-regenerator@^6.22.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f"
-  integrity sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=
+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:
-    regenerator-transform "^0.10.0"
+    object-assign "^4.1.1"
+    util "0.10.3"
 
-babel-plugin-transform-regexp-constructors@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz#6aa5dd0acc515db4be929bbcec4ed4c946c534a3"
-  integrity sha512-7IsQ6aQx6LAaOqy97/PthTf+5Nx9grZww3r6E62IdWe76Yr8KsuwVjxzqSPQvESJqTE3EMADQ9S0RtwWDGNG9Q==
+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=
 
-babel-plugin-transform-remove-console@^6.8.5:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780"
-  integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=
+astral-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+  integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
 
-babel-plugin-transform-remove-debugger@^6.8.5:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.9.4.tgz#42b727631c97978e1eb2d199a7aec84a18339ef2"
-  integrity sha1-QrcnYxyXl44estGZp67IShgznvI=
+astral-regex@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
+  integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
 
-babel-plugin-transform-remove-undefined@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz#94f052062054c707e8d094acefe79416b63452b1"
-  integrity sha512-O8v57tPMHkp89kA4ZfQEYds/pzgvz/QYerBJjIuL5/Jc7RnvMVRA5gJY9zFKP7WayW8WOSBV4vh8Y8FJRio+ow==
-  dependencies:
-    babel-helper-evaluate-path "^0.2.0"
+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==
 
-babel-plugin-transform-simplify-comparison-operators@^6.8.5:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.9.4.tgz#f62afe096cab0e1f68a2d753fdf283888471ceb9"
-  integrity sha1-9ir+CWyrDh9ootdT/fKDiIRxzrk=
+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==
 
-babel-plugin-transform-strict-mode@^6.24.1:
-  version "6.24.1"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758"
-  integrity sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=
+autoprefixer@^9.8.6:
+  version "9.8.6"
+  resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
+  integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==
   dependencies:
-    babel-runtime "^6.22.0"
-    babel-types "^6.24.1"
-
-babel-plugin-transform-undefined-to-void@^6.8.3:
-  version "6.9.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.9.4.tgz#be241ca81404030678b748717322b89d0c8fe280"
-  integrity sha1-viQcqBQEAwZ4t0hxcyK4nQyP4oA=
-
-babel-preset-env@^1.6.1:
-  version "1.7.0"
-  resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a"
-  integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==
-  dependencies:
-    babel-plugin-check-es2015-constants "^6.22.0"
-    babel-plugin-syntax-trailing-function-commas "^6.22.0"
-    babel-plugin-transform-async-to-generator "^6.22.0"
-    babel-plugin-transform-es2015-arrow-functions "^6.22.0"
-    babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
-    babel-plugin-transform-es2015-block-scoping "^6.23.0"
-    babel-plugin-transform-es2015-classes "^6.23.0"
-    babel-plugin-transform-es2015-computed-properties "^6.22.0"
-    babel-plugin-transform-es2015-destructuring "^6.23.0"
-    babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
-    babel-plugin-transform-es2015-for-of "^6.23.0"
-    babel-plugin-transform-es2015-function-name "^6.22.0"
-    babel-plugin-transform-es2015-literals "^6.22.0"
-    babel-plugin-transform-es2015-modules-amd "^6.22.0"
-    babel-plugin-transform-es2015-modules-commonjs "^6.23.0"
-    babel-plugin-transform-es2015-modules-systemjs "^6.23.0"
-    babel-plugin-transform-es2015-modules-umd "^6.23.0"
-    babel-plugin-transform-es2015-object-super "^6.22.0"
-    babel-plugin-transform-es2015-parameters "^6.23.0"
-    babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
-    babel-plugin-transform-es2015-spread "^6.22.0"
-    babel-plugin-transform-es2015-sticky-regex "^6.22.0"
-    babel-plugin-transform-es2015-template-literals "^6.22.0"
-    babel-plugin-transform-es2015-typeof-symbol "^6.23.0"
-    babel-plugin-transform-es2015-unicode-regex "^6.22.0"
-    babel-plugin-transform-exponentiation-operator "^6.22.0"
-    babel-plugin-transform-regenerator "^6.22.0"
-    browserslist "^3.2.6"
-    invariant "^2.2.2"
-    semver "^5.3.0"
+    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-preset-minify@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz#006566552d9b83834472273f306c0131062a0acc"
-  integrity sha512-mR8Q44RmMzm18bM2Lqd9uiPopzk5GDCtVuquNbLFmX6lOKnqWoenaNBxnWW0UhBFC75lEHTIgNGCbnsRI0pJVw==
-  dependencies:
-    babel-plugin-minify-builtins "^0.2.0"
-    babel-plugin-minify-constant-folding "^0.2.0"
-    babel-plugin-minify-dead-code-elimination "^0.2.0"
-    babel-plugin-minify-flip-comparisons "^0.2.0"
-    babel-plugin-minify-guarded-expressions "^0.2.0"
-    babel-plugin-minify-infinity "^0.2.0"
-    babel-plugin-minify-mangle-names "^0.2.0"
-    babel-plugin-minify-numeric-literals "^0.2.0"
-    babel-plugin-minify-replace "^0.2.0"
-    babel-plugin-minify-simplify "^0.2.0"
-    babel-plugin-minify-type-constructors "^0.2.0"
-    babel-plugin-transform-inline-consecutive-adds "^0.2.0"
-    babel-plugin-transform-member-expression-literals "^6.8.5"
-    babel-plugin-transform-merge-sibling-variables "^6.8.6"
-    babel-plugin-transform-minify-booleans "^6.8.3"
-    babel-plugin-transform-property-literals "^6.8.5"
-    babel-plugin-transform-regexp-constructors "^0.2.0"
-    babel-plugin-transform-remove-console "^6.8.5"
-    babel-plugin-transform-remove-debugger "^6.8.5"
-    babel-plugin-transform-remove-undefined "^0.2.0"
-    babel-plugin-transform-simplify-comparison-operators "^6.8.5"
-    babel-plugin-transform-undefined-to-void "^6.8.3"
-    lodash.isplainobject "^4.0.6"
-
-babel-register@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071"
-  integrity sha1-btAhFz4vy0htestFxgCahW9kcHE=
-  dependencies:
-    babel-core "^6.26.0"
-    babel-runtime "^6.26.0"
-    core-js "^2.5.0"
-    home-or-tmp "^2.0.0"
-    lodash "^4.17.4"
-    mkdirp "^0.5.1"
-    source-map-support "^0.4.15"
-
-babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
-  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
-  dependencies:
-    core-js "^2.4.0"
-    regenerator-runtime "^0.11.0"
-
-babel-template@^6.24.1, babel-template@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02"
-  integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=
-  dependencies:
-    babel-runtime "^6.26.0"
-    babel-traverse "^6.26.0"
-    babel-types "^6.26.0"
-    babylon "^6.18.0"
-    lodash "^4.17.4"
-
-babel-traverse@^6.24.1, babel-traverse@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee"
-  integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=
-  dependencies:
-    babel-code-frame "^6.26.0"
-    babel-messages "^6.23.0"
-    babel-runtime "^6.26.0"
-    babel-types "^6.26.0"
-    babylon "^6.18.0"
-    debug "^2.6.8"
-    globals "^9.18.0"
-    invariant "^2.2.2"
-    lodash "^4.17.4"
+awesomplete@^1.1.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/awesomplete/-/awesomplete-1.1.5.tgz#1b2b5dd106d3955595619c03da472a1dc0faf0af"
+  integrity sha512-UFw1mPW8NaSECDSTC36HbAOTpF9JK2wBUJcNn4MSvlNtK7SZ9N72gB+ajHtA6D1abYXRcszZnBA4nHBwvFwzHw==
 
-babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497"
-  integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=
+babel-loader@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3"
+  integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==
   dependencies:
-    babel-runtime "^6.26.0"
-    esutils "^2.0.2"
-    lodash "^4.17.4"
-    to-fast-properties "^1.0.3"
+    find-cache-dir "^2.1.0"
+    loader-utils "^1.4.0"
+    mkdirp "^0.5.3"
+    pify "^4.0.1"
+    schema-utils "^2.6.5"
 
-babylon@^6.18.0:
-  version "6.18.0"
-  resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
-  integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
+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"
 
-balanced-match@^0.4.2:
-  version "0.4.2"
-  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
-  integrity sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=
+bail@^1.0.0:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776"
+  integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==
 
 balanced-match@^1.0.0:
   version "1.0.0"
@@ -1018,9 +1320,9 @@ balanced-match@^1.0.0:
   integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 
 base64-js@^1.0.2:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
-  integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
+  integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
 
 base@^0.11.1:
   version "0.11.2"
@@ -1035,13 +1337,6 @@ base@^0.11.1:
     mixin-deep "^1.2.0"
     pascalcase "^0.1.1"
 
-bcrypt-pbkdf@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
-  integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
-  dependencies:
-    tweetnacl "^0.14.3"
-
 big.js@^5.2.2:
   version "5.2.2"
   resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@@ -1052,23 +1347,38 @@ binary-extensions@^1.0.0:
   resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
   integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
 
+binary-extensions@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
+  integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
+
+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"
+
 blazy@^1.8.2:
   version "1.8.2"
   resolved "https://registry.yarnpkg.com/blazy/-/blazy-1.8.2.tgz#50dfd638baaf9003efd6eb3a836aca54184ab6da"
   integrity sha1-UN/WOLqvkAPv1us6g2rKVBhKtto=
 
-block-stream@*:
-  version "0.0.9"
-  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
-  integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
-  dependencies:
-    inherits "~2.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.1.1, bn.js@^4.4.0:
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0:
   version "4.11.9"
   resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828"
   integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==
 
+bn.js@^5.1.1:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
+  integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
+
 brace-expansion@^1.1.7:
   version "1.1.11"
   resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -1093,6 +1403,13 @@ braces@^2.3.1, braces@^2.3.2:
     split-string "^3.0.2"
     to-regex "^3.0.1"
 
+braces@^3.0.1, braces@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
+  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
+  dependencies:
+    fill-range "^7.0.1"
+
 brorand@^1.0.1:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
@@ -1129,7 +1446,7 @@ browserify-des@^1.0.0:
     inherits "^2.0.1"
     safe-buffer "^5.1.2"
 
-browserify-rsa@^4.0.0:
+browserify-rsa@^4.0.0, browserify-rsa@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
   integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=
@@ -1138,17 +1455,19 @@ browserify-rsa@^4.0.0:
     randombytes "^2.0.1"
 
 browserify-sign@^4.0.0:
-  version "4.0.4"
-  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
-  integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=
-  dependencies:
-    bn.js "^4.1.1"
-    browserify-rsa "^4.0.0"
-    create-hash "^1.1.0"
-    create-hmac "^1.1.2"
-    elliptic "^6.0.0"
-    inherits "^2.0.1"
-    parse-asn1 "^5.0.0"
+  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"
@@ -1157,21 +1476,15 @@ browserify-zlib@^0.2.0:
   dependencies:
     pako "~1.0.5"
 
-browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6:
-  version "1.7.7"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
-  integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=
+browserslist@^4.12.0, browserslist@^4.8.5:
+  version "4.14.3"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.3.tgz#381f9e7f13794b2eb17e1761b4f118e8ae665a53"
+  integrity sha512-GcZPC5+YqyPO4SFnz48/B0YaCwS47Q9iPChRGi6t7HhflKBcINzFrJvRfC+jp30sRMKxF+d4EHGs27Z0XP1NaQ==
   dependencies:
-    caniuse-db "^1.0.30000639"
-    electron-to-chromium "^1.2.7"
-
-browserslist@^3.2.6:
-  version "3.2.8"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6"
-  integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==
-  dependencies:
-    caniuse-lite "^1.0.30000844"
-    electron-to-chromium "^1.3.47"
+    caniuse-lite "^1.0.30001131"
+    electron-to-chromium "^1.3.570"
+    escalade "^3.1.0"
+    node-releases "^1.1.61"
 
 buffer-from@^1.0.0:
   version "1.1.1"
@@ -1184,9 +1497,9 @@ buffer-xor@^1.0.3:
   integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
 
 buffer@^4.3.0:
-  version "4.9.1"
-  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
-  integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=
+  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"
@@ -1197,6 +1510,50 @@ builtin-status-codes@^3.0.0:
   resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
   integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
 
+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.0.5"
+  resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.0.5.tgz#69162833da29170d6732334643c60e005f5f17d0"
+  integrity sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==
+  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.0"
+    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"
@@ -1212,91 +1569,41 @@ cache-base@^1.0.1:
     union-value "^1.0.0"
     unset-value "^1.0.0"
 
-caller-path@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
-  integrity sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=
-  dependencies:
-    callsites "^0.2.0"
-
-callsites@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
-  integrity sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=
+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-keys@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
-  integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+camelcase-keys@^6.2.2:
+  version "6.2.2"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
+  integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
   dependencies:
-    camelcase "^2.0.0"
-    map-obj "^1.0.0"
-
-camelcase@^1.0.2:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
-  integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
+    camelcase "^5.3.1"
+    map-obj "^4.0.0"
+    quick-lru "^4.0.1"
 
-camelcase@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
-  integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
-
-camelcase@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
-  integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
+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==
 
-camelcase@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
-  integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
+camelcase@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e"
+  integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==
 
-caniuse-api@^1.5.2:
-  version "1.6.1"
-  resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c"
-  integrity sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=
-  dependencies:
-    browserslist "^1.3.6"
-    caniuse-db "^1.0.30000529"
-    lodash.memoize "^4.1.2"
-    lodash.uniq "^4.5.0"
-
-caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
-  version "1.0.30000969"
-  resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000969.tgz#e6aeca9b1bac88865990913a0b041f587180cd59"
-  integrity sha512-ttrmwpIXvEL/kg0JSg6Q+xEbMxAEcjZOOgZMGPcMe5JMYgi20Nvs9bqMRGfyIOQtd1jYa6yRWODIR6apj3xPQw==
-
-caniuse-lite@^1.0.30000844:
-  version "1.0.30000969"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000969.tgz#7664f571f2072657bde70b00a1fc1ba41f1942a9"
-  integrity sha512-Kus0yxkoAJgVc0bax7S4gLSlFifCa7MnSZL9p9VuS/HIKEL4seaqh28KIQAAO50cD/rJ5CiJkJFapkdDAlhFxQ==
-
-caseless@~0.12.0:
-  version "0.12.0"
-  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
-  integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
-
-center-align@^0.1.1:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
-  integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
-  dependencies:
-    align-text "^0.1.3"
-    lazy-cache "^1.0.3"
+caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001131:
+  version "1.0.30001135"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001135.tgz#995b1eb94404a3c9a0d7600c113c9bb27f2cd8aa"
+  integrity sha512-ziNcheTGTHlu9g34EVoHQdIu5g4foc8EsxMGC7Xkokmvw0dqNtX8BS8RgCgFBaAiSp2IdjvBxNdh0ssib28eVQ==
 
-chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
-  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
-  dependencies:
-    ansi-styles "^2.2.1"
-    escape-string-regexp "^1.0.2"
-    has-ansi "^2.0.0"
-    strip-ansi "^3.0.0"
-    supports-color "^2.0.0"
+ccount@^1.0.0:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17"
+  integrity sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==
 
-chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1:
+chalk@^2.0.0, 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==
@@ -1305,15 +1612,53 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1:
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
-chardet@^0.4.0:
-  version "0.4.2"
-  resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2"
-  integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=
+chalk@^4.0.0, chalk@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
+  integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
+  dependencies:
+    ansi-styles "^4.1.0"
+    supports-color "^7.1.0"
+
+character-entities-html4@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125"
+  integrity sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==
+
+character-entities-legacy@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1"
+  integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==
+
+character-entities@^1.0.0:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b"
+  integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==
 
-chokidar@^2.0.2:
-  version "2.1.6"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
-  integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==
+character-reference-invalid@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560"
+  integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==
+
+"chokidar@>=2.0.0 <4.0.0", chokidar@^3.4.1:
+  version "3.4.2"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.2.tgz#38dc8e658dec3809741eb3ef7bb0a47fe424232d"
+  integrity sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==
+  dependencies:
+    anymatch "~3.1.1"
+    braces "~3.0.2"
+    glob-parent "~5.1.0"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.4.0"
+  optionalDependencies:
+    fsevents "~2.1.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"
@@ -1330,9 +1675,21 @@ chokidar@^2.0.2:
     fsevents "^1.2.7"
 
 chownr@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
-  integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==
+  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.2"
+  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
+  integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==
+  dependencies:
+    tslib "^1.9.0"
 
 cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
   version "1.0.4"
@@ -1342,18 +1699,6 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
-circular-json@^0.3.1:
-  version "0.3.3"
-  resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
-  integrity sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==
-
-clap@^1.0.9:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
-  integrity sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==
-  dependencies:
-    chalk "^1.1.3"
-
 class-utils@^0.3.5:
   version "0.3.6"
   resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
@@ -1364,74 +1709,31 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
-cli-cursor@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
-  integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=
-  dependencies:
-    restore-cursor "^1.0.1"
-
-cli-cursor@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
-  integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
-  dependencies:
-    restore-cursor "^2.0.0"
-
-cli-width@^2.0.0:
+clean-stack@^2.0.0:
   version "2.2.0"
-  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
-  integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+  resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
+  integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
 
-cliui@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
-  integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
-  dependencies:
-    center-align "^0.1.1"
-    right-align "^0.1.1"
-    wordwrap "0.0.2"
-
-cliui@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
-  integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
-  dependencies:
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-    wrap-ansi "^2.0.0"
-
-clone-deep@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
-  integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
+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:
-    for-own "^1.0.0"
-    is-plain-object "^2.0.4"
-    kind-of "^6.0.0"
-    shallow-clone "^1.0.0"
-
-clone@^1.0.2:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
-  integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
-
-co@^4.6.0:
-  version "4.6.0"
-  resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
-  integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=
+    string-width "^3.1.0"
+    strip-ansi "^5.2.0"
+    wrap-ansi "^5.1.0"
 
-coa@~1.0.1:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.4.tgz#a9ef153660d6a86a8bdec0289a5c684d217432fd"
-  integrity sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=
+clone-regexp@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f"
+  integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==
   dependencies:
-    q "^1.1.2"
+    is-regexp "^2.0.0"
 
-code-point-at@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
-  integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+collapse-white-space@^1.0.2:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287"
+  integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==
 
 collection-visit@^1.0.0:
   version "1.0.0"
@@ -1441,64 +1743,39 @@ collection-visit@^1.0.0:
     map-visit "^1.0.0"
     object-visit "^1.0.0"
 
-color-convert@^1.3.0, color-convert@^1.9.0:
+color-convert@^1.9.0:
   version "1.9.3"
   resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
   integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
   dependencies:
     color-name "1.1.3"
 
+color-convert@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+  dependencies:
+    color-name "~1.1.4"
+
 color-name@1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
   integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
 
-color-name@^1.0.0:
+color-name@~1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
-color-string@^0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991"
-  integrity sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=
-  dependencies:
-    color-name "^1.0.0"
-
-color@^0.11.0:
-  version "0.11.4"
-  resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764"
-  integrity sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=
-  dependencies:
-    clone "^1.0.2"
-    color-convert "^1.3.0"
-    color-string "^0.3.0"
-
-colormin@^1.0.5:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133"
-  integrity sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=
-  dependencies:
-    color "^0.11.0"
-    css-color-names "0.0.4"
-    has "^1.0.1"
-
-colors@~1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
-  integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM=
-
-combined-stream@^1.0.6, combined-stream@~1.0.6:
-  version "1.0.8"
-  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
-  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
-  dependencies:
-    delayed-stream "~1.0.0"
+colorette@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
+  integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
 
-commander@^2.8.1:
-  version "2.20.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
-  integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
+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"
@@ -1515,7 +1792,7 @@ concat-map@0.0.1:
   resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
   integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
 
-concat-stream@^1.4.6, concat-stream@^1.6.0:
+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==
@@ -1525,17 +1802,15 @@ concat-stream@^1.4.6, concat-stream@^1.6.0:
     readable-stream "^2.2.2"
     typedarray "^0.0.6"
 
-console-browserify@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
-  integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=
-  dependencies:
-    date-now "^0.1.4"
+confusing-browser-globals@^1.0.9:
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd"
+  integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==
 
-console-control-strings@^1.0.0, console-control-strings@~1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
-  integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+console-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"
@@ -1547,37 +1822,63 @@ contains-path@^0.1.0:
   resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
   integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
 
-convert-source-map@^1.5.1:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
-  integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
+convert-source-map@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
+  integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==
   dependencies:
     safe-buffer "~5.1.1"
 
+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@^2.4.0, core-js@^2.5.0:
-  version "2.6.5"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
-  integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
+core-js-compat@^3.6.2:
+  version "3.6.5"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c"
+  integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==
+  dependencies:
+    browserslist "^4.8.5"
+    semver "7.0.0"
 
-core-util-is@1.0.2, core-util-is@~1.0.0:
+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@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3"
+  integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==
+  dependencies:
+    "@types/parse-json" "^4.0.0"
+    import-fresh "^3.2.1"
+    parse-json "^5.0.0"
+    path-type "^4.0.0"
+    yaml "^1.10.0"
+
 create-ecdh@^4.0.0:
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
-  integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
+  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.0.0"
+    elliptic "^6.5.3"
 
-create-hash@^1.1.0, create-hash@^1.1.2:
+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==
@@ -1588,7 +1889,7 @@ create-hash@^1.1.0, create-hash@^1.1.2:
     ripemd160 "^2.0.1"
     sha.js "^2.4.0"
 
-create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+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==
@@ -1600,22 +1901,25 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
     safe-buffer "^5.0.1"
     sha.js "^2.4.8"
 
-cross-spawn@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
-  integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI=
+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:
-    lru-cache "^4.0.1"
+    nice-try "^1.0.4"
+    path-key "^2.0.1"
+    semver "^5.5.0"
+    shebang-command "^1.2.0"
     which "^1.2.9"
 
-cross-spawn@^5.0.1, cross-spawn@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
-  integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
+cross-spawn@^7.0.2:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
   dependencies:
-    lru-cache "^4.0.1"
-    shebang-command "^1.2.0"
-    which "^1.2.9"
+    path-key "^3.1.0"
+    shebang-command "^2.0.0"
+    which "^2.0.1"
 
 crypto-browserify@^3.11.0:
   version "3.12.0"
@@ -1634,132 +1938,57 @@ crypto-browserify@^3.11.0:
     randombytes "^2.0.0"
     randomfill "^1.0.3"
 
-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-loader@^0.28.9:
-  version "0.28.11"
-  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.11.tgz#c3f9864a700be2711bb5a2462b2389b1a392dab7"
-  integrity sha512-wovHgjAx8ZIMGSL8pTys7edA1ClmzxHeY6n/d97gg5odgsxEgKjULPR0viqyC+FWMCL9sfqoC/QCUBo62tLvPg==
-  dependencies:
-    babel-code-frame "^6.26.0"
-    css-selector-tokenizer "^0.7.0"
-    cssnano "^3.10.0"
-    icss-utils "^2.1.0"
-    loader-utils "^1.0.2"
-    lodash.camelcase "^4.3.0"
-    object-assign "^4.1.1"
-    postcss "^5.0.6"
-    postcss-modules-extract-imports "^1.2.0"
-    postcss-modules-local-by-default "^1.2.0"
-    postcss-modules-scope "^1.1.0"
-    postcss-modules-values "^1.3.0"
-    postcss-value-parser "^3.3.0"
-    source-list-map "^2.0.0"
-
-css-selector-tokenizer@^0.7.0:
-  version "0.7.1"
-  resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz#a177271a8bca5019172f4f891fc6eed9cbf68d5d"
-  integrity sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==
-  dependencies:
-    cssesc "^0.1.0"
-    fastparse "^1.1.1"
-    regexpu-core "^1.0.0"
-
-cssesc@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4"
-  integrity sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=
-
-cssnano@^3.10.0:
-  version "3.10.0"
-  resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38"
-  integrity sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=
-  dependencies:
-    autoprefixer "^6.3.1"
-    decamelize "^1.1.2"
-    defined "^1.0.0"
-    has "^1.0.1"
-    object-assign "^4.0.1"
-    postcss "^5.0.14"
-    postcss-calc "^5.2.0"
-    postcss-colormin "^2.1.8"
-    postcss-convert-values "^2.3.4"
-    postcss-discard-comments "^2.0.4"
-    postcss-discard-duplicates "^2.0.1"
-    postcss-discard-empty "^2.0.1"
-    postcss-discard-overridden "^0.1.1"
-    postcss-discard-unused "^2.2.1"
-    postcss-filter-plugins "^2.0.0"
-    postcss-merge-idents "^2.1.5"
-    postcss-merge-longhand "^2.0.1"
-    postcss-merge-rules "^2.0.3"
-    postcss-minify-font-values "^1.0.2"
-    postcss-minify-gradients "^1.0.1"
-    postcss-minify-params "^1.0.4"
-    postcss-minify-selectors "^2.0.4"
-    postcss-normalize-charset "^1.1.0"
-    postcss-normalize-url "^3.0.7"
-    postcss-ordered-values "^2.1.0"
-    postcss-reduce-idents "^2.2.2"
-    postcss-reduce-initial "^1.0.0"
-    postcss-reduce-transforms "^1.0.3"
-    postcss-svgo "^2.1.1"
-    postcss-unique-selectors "^2.0.2"
-    postcss-value-parser "^3.2.3"
-    postcss-zindex "^2.0.1"
-
-csso@~2.3.1:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85"
-  integrity sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=
-  dependencies:
-    clap "^1.0.9"
-    source-map "^0.5.3"
-
-currently-unhandled@^0.4.1:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
-  integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
-  dependencies:
-    array-find-index "^1.0.1"
-
-d@1:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
-  integrity sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=
-  dependencies:
-    es5-ext "^0.10.9"
-
-dashdash@^1.12.0:
-  version "1.14.1"
-  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
-  integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
-  dependencies:
-    assert-plus "^1.0.0"
+css-loader@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.3.0.tgz#c888af64b2a5b2e85462c72c0f4a85c7e2e0821e"
+  integrity sha512-rdezjCjScIrsL8BSYszgT4s476IcNKt6yX69t0pHjJVnPUTDpn4WfIpDQTN3wCJvUvfsz/mFjuGOekf3PY3NUg==
+  dependencies:
+    camelcase "^6.0.0"
+    cssesc "^3.0.0"
+    icss-utils "^4.1.1"
+    loader-utils "^2.0.0"
+    postcss "^7.0.32"
+    postcss-modules-extract-imports "^2.0.0"
+    postcss-modules-local-by-default "^3.0.3"
+    postcss-modules-scope "^2.2.0"
+    postcss-modules-values "^3.0.0"
+    postcss-value-parser "^4.1.0"
+    schema-utils "^2.7.1"
+    semver "^7.3.2"
+
+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==
 
-date-now@^0.1.4:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b"
-  integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
+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.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
+debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
   version "2.6.9"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
   integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
   dependencies:
     ms "2.0.0"
 
-debug@^3.1.0, debug@^3.2.6:
-  version "3.2.6"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
-  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1"
+  integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==
   dependencies:
-    ms "^2.1.1"
+    ms "2.1.2"
 
-decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
+decamelize-keys@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
+  integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
+  dependencies:
+    decamelize "^1.1.0"
+    map-obj "^1.0.0"
+
+decamelize@^1.1.0, decamelize@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@@ -1769,17 +1998,12 @@ decode-uri-component@^0.2.0:
   resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
   integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
 
-deep-extend@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
-  integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
-
-deep-is@~0.1.3:
+deep-is@^0.1.3:
   version "0.1.3"
   resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
   integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
 
-define-properties@^1.1.2:
+define-properties@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
   integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
@@ -1808,40 +2032,18 @@ define-property@^2.0.2:
     is-descriptor "^1.0.2"
     isobject "^3.0.1"
 
-defined@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
-  integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
-
-delayed-stream@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
-  integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
-
-delegates@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
-  integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
-
 des.js@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
-  integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=
+  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"
 
-detect-indent@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
-  integrity sha1-920GQ1LN9Docts5hnE7jqUdd4gg=
-  dependencies:
-    repeating "^2.0.0"
-
-detect-libc@^1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
-  integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
+detect-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=
 
 diffie-hellman@^5.0.0:
   version "5.0.3"
@@ -1852,7 +2054,14 @@ diffie-hellman@^5.0.0:
     miller-rabin "^4.0.0"
     randombytes "^2.0.0"
 
-doctrine@1.5.0, doctrine@^1.2.2:
+dir-glob@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+  integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+  dependencies:
+    path-type "^4.0.0"
+
+doctrine@1.5.0:
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
   integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
@@ -1860,32 +2069,67 @@ doctrine@1.5.0, doctrine@^1.2.2:
     esutils "^2.0.2"
     isarray "^1.0.0"
 
-doctrine@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
-  integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+doctrine@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+  integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
   dependencies:
     esutils "^2.0.2"
 
+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==
 
-ecc-jsbn@~0.1.1:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
-  integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
+domelementtype@1, domelementtype@^1.3.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.0.2"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.0.2.tgz#f3b6e549201e46f588b59463dd77187131fe6971"
+  integrity sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==
+
+domhandler@^2.3.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
+  integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
   dependencies:
-    jsbn "~0.1.0"
-    safer-buffer "^2.1.0"
+    domelementtype "1"
+
+domutils@^1.5.1:
+  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"
+
+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"
 
-electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47:
-  version "1.3.135"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.135.tgz#f5799b95f2bcd8de17cde47d63392d83a4477041"
-  integrity sha512-xXLNstRdVsisPF3pL3H9TVZo2XkMILfqtD6RiWIUmDK2sFX1Bjwqmd8LBp0Kuo2FgKO63JXPoEVGm8WyYdwP0Q==
+electron-to-chromium@^1.3.570:
+  version "1.3.570"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.570.tgz#3f5141cc39b4e3892a276b4889980dabf1d29c7f"
+  integrity sha512-Y6OCoVQgFQBP5py6A/06+yWxUZHDlNr/gNDGatjH8AZqXl8X0tE4LfjLJsXGz/JmWJz8a6K7bR1k+QzZ+k//fg==
 
-elliptic@^6.0.0:
+elliptic@^6.5.3:
   version "6.5.3"
   resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
   integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
@@ -1898,325 +2142,284 @@ elliptic@^6.0.0:
     minimalistic-assert "^1.0.0"
     minimalistic-crypto-utils "^1.0.0"
 
-emojis-list@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
-  integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
+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==
 
-enhanced-resolve@^3.4.0:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz#0421e339fd71419b3da13d129b3979040230476e"
-  integrity sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=
-  dependencies:
-    graceful-fs "^4.1.2"
-    memory-fs "^0.4.0"
-    object-assign "^4.0.1"
-    tapable "^0.2.7"
+emoji-regex@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+  integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
 
-errno@^0.1.3:
-  version "0.1.7"
-  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
-  integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
-  dependencies:
-    prr "~1.0.1"
+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==
 
-error-ex@^1.2.0:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
-  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+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:
-    is-arrayish "^0.2.1"
+    once "^1.4.0"
 
-es-abstract@^1.7.0:
-  version "1.13.0"
-  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9"
-  integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==
+enhanced-resolve@^4.1.1, enhanced-resolve@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126"
+  integrity sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==
   dependencies:
-    es-to-primitive "^1.2.0"
-    function-bind "^1.1.1"
-    has "^1.0.3"
-    is-callable "^1.1.4"
-    is-regex "^1.0.4"
-    object-keys "^1.0.12"
+    graceful-fs "^4.1.2"
+    memory-fs "^0.5.0"
+    tapable "^1.0.0"
 
-es-to-primitive@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
-  integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
+enquirer@^2.3.5:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
+  integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
   dependencies:
-    is-callable "^1.1.4"
-    is-date-object "^1.0.1"
-    is-symbol "^1.0.2"
+    ansi-colors "^4.1.1"
 
-es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14:
-  version "0.10.50"
-  resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.50.tgz#6d0e23a0abdb27018e5ac4fd09b412bc5517a778"
-  integrity sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==
-  dependencies:
-    es6-iterator "~2.0.3"
-    es6-symbol "~3.1.1"
-    next-tick "^1.0.0"
+entities@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
+  integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
 
-es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3:
+entities@^2.0.0:
   version "2.0.3"
-  resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7"
-  integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c=
-  dependencies:
-    d "1"
-    es5-ext "^0.10.35"
-    es6-symbol "^3.1.1"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
+  integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==
 
-es6-map@^0.1.3:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0"
-  integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=
+errno@^0.1.3, errno@~0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+  integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
   dependencies:
-    d "1"
-    es5-ext "~0.10.14"
-    es6-iterator "~2.0.1"
-    es6-set "~0.1.5"
-    es6-symbol "~3.1.1"
-    event-emitter "~0.3.5"
+    prr "~1.0.1"
 
-es6-set@~0.1.5:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1"
-  integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=
+error-ex@^1.2.0, 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:
-    d "1"
-    es5-ext "~0.10.14"
-    es6-iterator "~2.0.1"
-    es6-symbol "3.1.1"
-    event-emitter "~0.3.5"
+    is-arrayish "^0.2.1"
 
-es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77"
-  integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=
+es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
+  version "1.17.6"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.6.tgz#9142071707857b2cacc7b89ecb670316c3e2d52a"
+  integrity sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==
   dependencies:
-    d "1"
-    es5-ext "~0.10.14"
-
-es6-weak-map@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f"
-  integrity sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=
+    es-to-primitive "^1.2.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.1"
+    is-callable "^1.2.0"
+    is-regex "^1.1.0"
+    object-inspect "^1.7.0"
+    object-keys "^1.1.1"
+    object.assign "^4.1.0"
+    string.prototype.trimend "^1.0.1"
+    string.prototype.trimstart "^1.0.1"
+
+es-abstract@^1.18.0-next.0:
+  version "1.18.0-next.0"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.0.tgz#b302834927e624d8e5837ed48224291f2c66e6fc"
+  integrity sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==
+  dependencies:
+    es-to-primitive "^1.2.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    has-symbols "^1.0.1"
+    is-callable "^1.2.0"
+    is-negative-zero "^2.0.0"
+    is-regex "^1.1.1"
+    object-inspect "^1.8.0"
+    object-keys "^1.1.1"
+    object.assign "^4.1.0"
+    string.prototype.trimend "^1.0.1"
+    string.prototype.trimstart "^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:
-    d "1"
-    es5-ext "^0.10.14"
-    es6-iterator "^2.0.1"
-    es6-symbol "^3.1.1"
+    is-callable "^1.1.4"
+    is-date-object "^1.0.1"
+    is-symbol "^1.0.2"
+
+escalade@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.0.tgz#e8e2d7c7a8b76f6ee64c2181d6b8151441602d4e"
+  integrity sha512-mAk+hPSO8fLDkhV7V0dXazH5pDc6MrjBTPyD3VeKzxnVFjH1MIxbCdqGZB9O8+EwWakZs3ZCbDS4IpRt79V1ig==
 
-escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+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=
 
-escope@^3.6.0:
-  version "3.6.0"
-  resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
-  integrity sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=
-  dependencies:
-    es6-map "^0.1.3"
-    es6-weak-map "^2.0.1"
-    esrecurse "^4.1.0"
-    estraverse "^4.1.1"
-
-eslint-config-airbnb-base@^12.1.0:
-  version "12.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944"
-  integrity sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==
+eslint-config-airbnb-base@^14.2.0:
+  version "14.2.0"
+  resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.0.tgz#fe89c24b3f9dc8008c9c0d0d88c28f95ed65e9c4"
+  integrity sha512-Snswd5oC6nJaevs3nZoLSTvGJBvzTfnBqOIArkf3cbyTyq9UD79wOk8s+RiL6bhca0p/eRO6veczhf6A/7Jy8Q==
   dependencies:
-    eslint-restricted-globals "^0.1.1"
+    confusing-browser-globals "^1.0.9"
+    object.assign "^4.1.0"
+    object.entries "^1.1.2"
 
-eslint-import-resolver-node@^0.3.2:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a"
-  integrity sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==
+eslint-import-resolver-node@^0.3.3:
+  version "0.3.4"
+  resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
+  integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
   dependencies:
     debug "^2.6.9"
-    resolve "^1.5.0"
+    resolve "^1.13.1"
 
-eslint-module-utils@^2.4.0:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.0.tgz#8b93499e9b00eab80ccb6614e69f03678e84e09a"
-  integrity sha512-14tltLm38Eu3zS+mt0KvILC3q8jyIAH518MlG+HO0p+yK885Lb1UHTY/UgR91eOyGdmxAPb+OLoW4znqIT6Ndw==
+eslint-module-utils@^2.6.0:
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6"
+  integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==
   dependencies:
-    debug "^2.6.8"
+    debug "^2.6.9"
     pkg-dir "^2.0.0"
 
-eslint-plugin-import@^2.8.0:
-  version "2.17.2"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.17.2.tgz#d227d5c6dc67eca71eb590d2bb62fb38d86e9fcb"
-  integrity sha512-m+cSVxM7oLsIpmwNn2WXTJoReOF9f/CtLMo7qOVmKd1KntBy0hEcuNZ3erTmWjx+DxRO0Zcrm5KwAvI9wHcV5g==
+eslint-plugin-import@^2.22.0:
+  version "2.22.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.22.0.tgz#92f7736fe1fde3e2de77623c838dd992ff5ffb7e"
+  integrity sha512-66Fpf1Ln6aIS5Gr/55ts19eUuoDhAbZgnr6UxK5hbDx6l/QgQgx61AePq+BV4PP2uXQFClgMVzep5zZ94qqsxg==
   dependencies:
-    array-includes "^3.0.3"
+    array-includes "^3.1.1"
+    array.prototype.flat "^1.2.3"
     contains-path "^0.1.0"
     debug "^2.6.9"
     doctrine "1.5.0"
-    eslint-import-resolver-node "^0.3.2"
-    eslint-module-utils "^2.4.0"
+    eslint-import-resolver-node "^0.3.3"
+    eslint-module-utils "^2.6.0"
     has "^1.0.3"
-    lodash "^4.17.11"
     minimatch "^3.0.4"
+    object.values "^1.1.1"
     read-pkg-up "^2.0.0"
-    resolve "^1.10.0"
-
-eslint-restricted-globals@^0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
-  integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=
+    resolve "^1.17.0"
+    tsconfig-paths "^3.9.0"
 
-eslint-scope@^3.7.1:
-  version "3.7.3"
-  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535"
-  integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA==
+eslint-scope@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
+  integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
   dependencies:
     esrecurse "^4.1.0"
     estraverse "^4.1.1"
 
-eslint-visitor-keys@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
-  integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
-
-eslint@^2.7.0:
-  version "2.13.1"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11"
-  integrity sha1-5MyPoPAJ+4KaquI4VaKTYL4fbBE=
-  dependencies:
-    chalk "^1.1.3"
-    concat-stream "^1.4.6"
-    debug "^2.1.1"
-    doctrine "^1.2.2"
-    es6-map "^0.1.3"
-    escope "^3.6.0"
-    espree "^3.1.6"
-    estraverse "^4.2.0"
-    esutils "^2.0.2"
-    file-entry-cache "^1.1.1"
-    glob "^7.0.3"
-    globals "^9.2.0"
-    ignore "^3.1.2"
-    imurmurhash "^0.1.4"
-    inquirer "^0.12.0"
-    is-my-json-valid "^2.10.0"
-    is-resolvable "^1.0.0"
-    js-yaml "^3.5.1"
-    json-stable-stringify "^1.0.0"
-    levn "^0.3.0"
-    lodash "^4.0.0"
-    mkdirp "^0.5.0"
-    optionator "^0.8.1"
-    path-is-absolute "^1.0.0"
-    path-is-inside "^1.0.1"
-    pluralize "^1.2.1"
-    progress "^1.1.8"
-    require-uncached "^1.0.2"
-    shelljs "^0.6.0"
-    strip-json-comments "~1.0.1"
-    table "^3.7.8"
-    text-table "~0.2.0"
-    user-home "^2.0.0"
-
-eslint@^4.16.0:
-  version "4.19.1"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300"
-  integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==
-  dependencies:
-    ajv "^5.3.0"
-    babel-code-frame "^6.22.0"
-    chalk "^2.1.0"
-    concat-stream "^1.6.0"
-    cross-spawn "^5.1.0"
-    debug "^3.1.0"
-    doctrine "^2.1.0"
-    eslint-scope "^3.7.1"
-    eslint-visitor-keys "^1.0.0"
-    espree "^3.5.4"
-    esquery "^1.0.0"
+eslint-scope@^5.1.0:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+  integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+  dependencies:
+    esrecurse "^4.3.0"
+    estraverse "^4.1.1"
+
+eslint-utils@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
+  integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
+  dependencies:
+    eslint-visitor-keys "^1.1.0"
+
+eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
+  integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
+
+eslint@^7.9.0:
+  version "7.9.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.9.0.tgz#522aeccc5c3a19017cf0cb46ebfd660a79acf337"
+  integrity sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@eslint/eslintrc" "^0.1.3"
+    ajv "^6.10.0"
+    chalk "^4.0.0"
+    cross-spawn "^7.0.2"
+    debug "^4.0.1"
+    doctrine "^3.0.0"
+    enquirer "^2.3.5"
+    eslint-scope "^5.1.0"
+    eslint-utils "^2.1.0"
+    eslint-visitor-keys "^1.3.0"
+    espree "^7.3.0"
+    esquery "^1.2.0"
     esutils "^2.0.2"
-    file-entry-cache "^2.0.0"
+    file-entry-cache "^5.0.1"
     functional-red-black-tree "^1.0.1"
-    glob "^7.1.2"
-    globals "^11.0.1"
-    ignore "^3.3.3"
+    glob-parent "^5.0.0"
+    globals "^12.1.0"
+    ignore "^4.0.6"
+    import-fresh "^3.0.0"
     imurmurhash "^0.1.4"
-    inquirer "^3.0.6"
-    is-resolvable "^1.0.0"
-    js-yaml "^3.9.1"
+    is-glob "^4.0.0"
+    js-yaml "^3.13.1"
     json-stable-stringify-without-jsonify "^1.0.1"
-    levn "^0.3.0"
-    lodash "^4.17.4"
-    minimatch "^3.0.2"
-    mkdirp "^0.5.1"
+    levn "^0.4.1"
+    lodash "^4.17.19"
+    minimatch "^3.0.4"
     natural-compare "^1.4.0"
-    optionator "^0.8.2"
-    path-is-inside "^1.0.2"
-    pluralize "^7.0.0"
+    optionator "^0.9.1"
     progress "^2.0.0"
-    regexpp "^1.0.1"
-    require-uncached "^1.0.3"
-    semver "^5.3.0"
-    strip-ansi "^4.0.0"
-    strip-json-comments "~2.0.1"
-    table "4.0.2"
-    text-table "~0.2.0"
-
-espree@^3.1.6, espree@^3.5.4:
-  version "3.5.4"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7"
-  integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==
-  dependencies:
-    acorn "^5.5.0"
-    acorn-jsx "^3.0.0"
-
-esprima@^2.6.0:
-  version "2.7.3"
-  resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
-  integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=
+    regexpp "^3.1.0"
+    semver "^7.2.1"
+    strip-ansi "^6.0.0"
+    strip-json-comments "^3.1.0"
+    table "^5.2.3"
+    text-table "^0.2.0"
+    v8-compile-cache "^2.0.3"
+
+espree@^7.3.0:
+  version "7.3.0"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348"
+  integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==
+  dependencies:
+    acorn "^7.4.0"
+    acorn-jsx "^5.2.0"
+    eslint-visitor-keys "^1.3.0"
 
 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==
 
-esquery@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
-  integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+esquery@^1.2.0:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57"
+  integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==
   dependencies:
-    estraverse "^4.0.0"
+    estraverse "^5.1.0"
 
-esrecurse@^4.1.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
-  integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+esrecurse@^4.1.0, esrecurse@^4.3.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 "^4.1.0"
+    estraverse "^5.2.0"
 
-estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
-  integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
+estraverse@^4.1.1:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
 
-esutils@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
-  integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+estraverse@^5.1.0, 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==
 
-event-emitter@~0.3.5:
-  version "0.3.5"
-  resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39"
-  integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=
-  dependencies:
-    d "1"
-    es5-ext "~0.10.14"
+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==
 
 events@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
-  integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379"
+  integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==
 
 evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
   version "1.0.3"
@@ -2226,23 +2429,12 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
     md5.js "^1.3.4"
     safe-buffer "^5.1.1"
 
-execa@^0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
-  integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
+execall@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45"
+  integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==
   dependencies:
-    cross-spawn "^5.0.1"
-    get-stream "^3.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"
-
-exit-hook@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
-  integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=
+    clone-regexp "^2.1.0"
 
 expand-brackets@^2.1.4:
   version "2.1.4"
@@ -2257,6 +2449,13 @@ expand-brackets@^2.1.4:
     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"
+
 extend-shallow@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
@@ -2272,20 +2471,11 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
     assign-symbols "^1.0.0"
     is-extendable "^1.0.1"
 
-extend@~3.0.2:
+extend@^3.0.0:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
   integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
 
-external-editor@^2.0.4:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
-  integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==
-  dependencies:
-    chardet "^0.4.0"
-    iconv-lite "^0.4.17"
-    tmp "^0.0.33"
-
 extglob@^2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
@@ -2300,81 +2490,56 @@ extglob@^2.0.4:
     snapdragon "^0.8.1"
     to-regex "^3.0.1"
 
-extract-text-webpack-plugin@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.2.tgz#5f043eaa02f9750a9258b78c0a6e0dc1408fb2f7"
-  integrity sha512-bt/LZ4m5Rqt/Crl2HiKuAl/oqg0psx1tsTLkvWbJen1CtD+fftkZhMaQ9HOtY2gWsl2Wq+sABmMVi9z3DhKWQQ==
-  dependencies:
-    async "^2.4.1"
-    loader-utils "^1.1.0"
-    schema-utils "^0.3.0"
-    webpack-sources "^1.0.1"
-
-extsprintf@1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
-  integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
-
-extsprintf@^1.2.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
-  integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
-
-fast-deep-equal@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
-  integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=
+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-deep-equal@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
-  integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+fast-glob@^3.1.1, fast-glob@^3.2.4:
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
+  integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.0"
+    merge2 "^1.3.0"
+    micromatch "^4.0.2"
+    picomatch "^2.2.1"
 
 fast-json-stable-stringify@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
-  integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
 
-fast-levenshtein@~2.0.4:
+fast-levenshtein@^2.0.6:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
   integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
 
-fastparse@^1.1.1:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
-  integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
-
-figures@^1.3.5:
-  version "1.7.0"
-  resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e"
-  integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=
-  dependencies:
-    escape-string-regexp "^1.0.5"
-    object-assign "^4.1.0"
+fastest-levenshtein@^1.0.12:
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
+  integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
 
-figures@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
-  integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+fastq@^1.6.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481"
+  integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q==
   dependencies:
-    escape-string-regexp "^1.0.5"
+    reusify "^1.0.4"
 
-file-entry-cache@^1.1.1:
-  version "1.3.1"
-  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8"
-  integrity sha1-RMYepgeuS+nBQC9B9EJwy/4zT/g=
-  dependencies:
-    flat-cache "^1.2.1"
-    object-assign "^4.0.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-entry-cache@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
-  integrity sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=
+file-entry-cache@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+  integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
   dependencies:
-    flat-cache "^1.2.1"
-    object-assign "^4.0.1"
+    flat-cache "^2.0.1"
 
 file-loader@^1.1.6:
   version "1.1.11"
@@ -2384,6 +2549,11 @@ file-loader@^1.1.6:
     loader-utils "^1.0.2"
     schema-utils "^0.4.5"
 
+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"
@@ -2394,22 +2564,30 @@ fill-range@^4.0.0:
     repeat-string "^1.6.1"
     to-regex-range "^2.1.0"
 
-find-cache-dir@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f"
-  integrity sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=
+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"
+
+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 "^1.0.0"
-    pkg-dir "^2.0.0"
+    make-dir "^2.0.0"
+    pkg-dir "^3.0.0"
 
-find-up@^1.0.0:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
-  integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+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:
-    path-exists "^2.0.0"
-    pinkie-promise "^2.0.0"
+    commondir "^1.0.1"
+    make-dir "^3.0.2"
+    pkg-dir "^4.1.0"
 
 find-up@^2.0.0, find-up@^2.1.0:
   version "2.1.0"
@@ -2418,57 +2596,63 @@ find-up@^2.0.0, find-up@^2.1.0:
   dependencies:
     locate-path "^2.0.0"
 
-flat-cache@^1.2.1:
-  version "1.3.4"
-  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f"
-  integrity sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==
+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, find-up@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+  integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
   dependencies:
-    circular-json "^0.3.1"
-    graceful-fs "^4.1.2"
-    rimraf "~2.6.2"
-    write "^0.2.1"
+    locate-path "^5.0.0"
+    path-exists "^4.0.0"
 
-flatten@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
-  integrity sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=
+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"
 
-for-in@^0.1.3:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
-  integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
+flat-cache@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+  integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+  dependencies:
+    flatted "^2.0.0"
+    rimraf "2.6.3"
+    write "1.0.3"
 
-for-in@^1.0.1, 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=
+flatted@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
+  integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
 
-for-own@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
-  integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
+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:
-    for-in "^1.0.1"
+    inherits "^2.0.3"
+    readable-stream "^2.3.6"
 
-forever-agent@~0.6.1:
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
-  integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+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=
 
 fork-awesome@^1.1.7:
   version "1.1.7"
   resolved "https://registry.yarnpkg.com/fork-awesome/-/fork-awesome-1.1.7.tgz#1427da1cac3d1713046ee88427e5fcecb9501d21"
   integrity sha512-IHI7XCSXrKfUIWslse8c/PaaVDT1oBaYge+ju40ihL2ooiQeBpTr4wvIXhgTd2NuhntlvX+M5jYHAPTzNlmv0g==
 
-form-data@~2.3.2:
-  version "2.3.3"
-  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
-  integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
-  dependencies:
-    asynckit "^0.4.0"
-    combined-stream "^1.0.6"
-    mime-types "^2.1.12"
-
 fragment-cache@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
@@ -2476,28 +2660,30 @@ fragment-cache@^0.2.1:
   dependencies:
     map-cache "^0.2.2"
 
-front-matter@2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/front-matter/-/front-matter-2.1.2.tgz#f75983b9f2f413be658c93dfd7bd8ce4078f5cdb"
-  integrity sha1-91mDufL0E75ljJPf172M5AePXNs=
+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:
-    js-yaml "^3.4.6"
+    inherits "^2.0.1"
+    readable-stream "^2.0.0"
 
-fs-extra@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291"
-  integrity sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=
+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:
-    graceful-fs "^4.1.2"
-    jsonfile "^3.0.0"
-    universalify "^0.1.0"
+    minipass "^3.0.0"
 
-fs-minipass@^1.2.5:
-  version "1.2.6"
-  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
-  integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
+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:
-    minipass "^2.2.1"
+    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"
@@ -2505,22 +2691,17 @@ fs.realpath@^1.0.0:
   integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
 
 fsevents@^1.2.7:
-  version "1.2.9"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
-  integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
+  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"
-    node-pre-gyp "^0.12.0"
 
-fstream@^1.0.0, fstream@^1.0.12:
-  version "1.0.12"
-  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
-  integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
-  dependencies:
-    graceful-fs "^4.1.2"
-    inherits "~2.0.0"
-    mkdirp ">=0.5 0"
-    rimraf "2"
+fsevents@~2.1.2:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
+  integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
 
 function-bind@^1.1.1:
   version "1.1.1"
@@ -2532,68 +2713,26 @@ functional-red-black-tree@^1.0.1:
   resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
   integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
 
-gauge@~2.7.3:
-  version "2.7.4"
-  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
-  integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
-  dependencies:
-    aproba "^1.0.3"
-    console-control-strings "^1.0.0"
-    has-unicode "^2.0.0"
-    object-assign "^4.1.0"
-    signal-exit "^3.0.0"
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
-    wide-align "^1.1.0"
-
-gaze@^1.0.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
-  integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
-  dependencies:
-    globule "^1.0.0"
-
-generate-function@^2.0.0:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f"
-  integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==
-  dependencies:
-    is-property "^1.0.2"
-
-generate-object-property@^1.1.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0"
-  integrity sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=
-  dependencies:
-    is-property "^1.0.0"
-
-get-caller-file@^1.0.1:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
-  integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+gensync@^1.0.0-beta.1:
+  version "1.0.0-beta.1"
+  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269"
+  integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==
 
-get-stdin@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
-  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+get-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-stream@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
-  integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
+get-stdin@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
+  integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
 
 get-value@^2.0.3, get-value@^2.0.6:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
   integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
 
-getpass@^0.1.1:
-  version "0.1.7"
-  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
-  integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
-  dependencies:
-    assert-plus "^1.0.0"
-
 glob-parent@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@@ -2602,10 +2741,17 @@ glob-parent@^3.1.0:
     is-glob "^3.1.0"
     path-dirname "^1.0.0"
 
-glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1:
-  version "7.1.4"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
-  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
+  integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
+  dependencies:
+    is-glob "^4.0.1"
+
+glob@^7.1.3, glob@^7.1.4:
+  version "7.1.6"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
+  integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
   dependencies:
     fs.realpath "^1.0.0"
     inflight "^1.0.4"
@@ -2614,81 +2760,102 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1:
     once "^1.3.0"
     path-is-absolute "^1.0.0"
 
-globals@^11.0.1:
-  version "11.12.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
-  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+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"
 
-globals@^9.18.0, globals@^9.2.0:
-  version "9.18.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
-  integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
+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"
 
-globule@^1.0.0:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
-  integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
+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:
-    glob "~7.1.1"
-    lodash "~4.17.10"
-    minimatch "~3.0.2"
+    expand-tilde "^2.0.2"
+    homedir-polyfill "^1.0.1"
+    ini "^1.3.4"
+    is-windows "^1.0.1"
+    which "^1.2.14"
 
-gonzales-pe-sl@^4.2.3:
-  version "4.2.3"
-  resolved "https://registry.yarnpkg.com/gonzales-pe-sl/-/gonzales-pe-sl-4.2.3.tgz#6a868bc380645f141feeb042c6f97fcc71b59fe6"
-  integrity sha1-aoaLw4BkXxQf7rBCxvl/zHG1n+Y=
+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:
-    minimist "1.1.x"
+    ini "^1.3.5"
+    kind-of "^6.0.2"
+    which "^1.3.1"
 
-graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6:
-  version "4.1.15"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
-  integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
+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==
 
-har-schema@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
-  integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
+globals@^12.1.0:
+  version "12.4.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8"
+  integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==
+  dependencies:
+    type-fest "^0.8.1"
 
-har-validator@~5.1.0:
-  version "5.1.3"
-  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
-  integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+globby@^11.0.1:
+  version "11.0.1"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357"
+  integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==
   dependencies:
-    ajv "^6.5.5"
-    har-schema "^2.0.0"
+    array-union "^2.1.0"
+    dir-glob "^3.0.1"
+    fast-glob "^3.1.1"
+    ignore "^5.1.4"
+    merge2 "^1.3.0"
+    slash "^3.0.0"
 
-has-ansi@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
-  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+globjoin@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
+  integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=
+
+gonzales-pe@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3"
+  integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ==
   dependencies:
-    ansi-regex "^2.0.0"
+    minimist "^1.2.5"
 
-has-flag@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
-  integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2:
+  version "4.2.4"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
+  integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
 
-has-flag@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
-  integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=
+hard-rejection@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
+  integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
 
 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-symbols@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
-  integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
+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-unicode@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
-  integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
+has-symbols@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
+  integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
 
 has-value@^0.3.1:
   version "0.3.1"
@@ -2721,7 +2888,7 @@ has-values@^1.0.0:
     is-number "^3.0.0"
     kind-of "^4.0.0"
 
-has@^1.0.1, has@^1.0.3:
+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==
@@ -2729,12 +2896,13 @@ has@^1.0.1, has@^1.0.3:
     function-bind "^1.1.1"
 
 hash-base@^3.0.0:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
-  integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=
+  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.1"
-    safe-buffer "^5.0.1"
+    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"
@@ -2753,100 +2921,107 @@ hmac-drbg@^1.0.0:
     minimalistic-assert "^1.0.0"
     minimalistic-crypto-utils "^1.0.1"
 
-home-or-tmp@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8"
-  integrity sha1-42w/LSyufXRqhX440Y1fMqeILbg=
+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:
-    os-homedir "^1.0.0"
-    os-tmpdir "^1.0.1"
+    parse-passwd "^1.0.0"
 
 hosted-git-info@^2.1.4:
-  version "2.7.1"
-  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
-  integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
-
-html-comment-regex@^1.1.0:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7"
-  integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==
+  version "2.8.8"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
+  integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
 
-http-signature@~1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
-  integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
-  dependencies:
-    assert-plus "^1.0.0"
-    jsprim "^1.2.2"
-    sshpk "^1.7.0"
+html-tags@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140"
+  integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==
+
+htmlparser2@^3.10.0:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
+  integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
+  dependencies:
+    domelementtype "^1.3.1"
+    domhandler "^2.3.0"
+    domutils "^1.5.1"
+    entities "^1.1.1"
+    inherits "^2.0.1"
+    readable-stream "^3.1.1"
 
 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.17, iconv-lite@^0.4.4:
-  version "0.4.24"
-  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
-  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
-  dependencies:
-    safer-buffer ">= 2.1.2 < 3"
-
-icss-replace-symbols@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded"
-  integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=
-
-icss-utils@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962"
-  integrity sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=
+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 "^6.0.1"
+    postcss "^7.0.14"
 
 ieee754@^1.1.4:
   version "1.1.13"
   resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
   integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
 
-ignore-walk@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
-  integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
+iferr@^0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
+  integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
+
+ignore@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+  integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
+ignore@^5.1.4, ignore@^5.1.8:
+  version "5.1.8"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
+  integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
+
+import-fresh@^3.0.0, import-fresh@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
+  integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
   dependencies:
-    minimatch "^3.0.4"
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+import-lazy@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
+  integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==
 
-ignore@^3.1.2, ignore@^3.3.3:
-  version "3.3.10"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
-  integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
+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=
 
-in-publish@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
-  integrity sha1-4g/146KvwmkDILbcVSaCqcf631E=
-
-indent-string@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
-  integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
-  dependencies:
-    repeating "^2.0.0"
+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=
 
-indexof@0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
-  integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=
+infer-owner@^1.0.3, 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"
@@ -2856,7 +3031,7 @@ inflight@^1.0.4:
     once "^1.3.0"
     wrappy "1"
 
-inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
+inherits@2, inherits@^2.0.0, 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==
@@ -2871,72 +3046,23 @@ inherits@2.0.3:
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
   integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
 
-ini@~1.3.0:
+ini@^1.3.4, ini@^1.3.5:
   version "1.3.5"
   resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
   integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
 
-inquirer@^0.12.0:
-  version "0.12.0"
-  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e"
-  integrity sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=
-  dependencies:
-    ansi-escapes "^1.1.0"
-    ansi-regex "^2.0.0"
-    chalk "^1.0.0"
-    cli-cursor "^1.0.1"
-    cli-width "^2.0.0"
-    figures "^1.3.5"
-    lodash "^4.3.0"
-    readline2 "^1.0.1"
-    run-async "^0.1.0"
-    rx-lite "^3.1.2"
-    string-width "^1.0.1"
-    strip-ansi "^3.0.0"
-    through "^2.3.6"
-
-inquirer@^3.0.6:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9"
-  integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==
-  dependencies:
-    ansi-escapes "^3.0.0"
-    chalk "^2.0.0"
-    cli-cursor "^2.1.0"
-    cli-width "^2.0.0"
-    external-editor "^2.0.4"
-    figures "^2.0.0"
-    lodash "^4.3.0"
-    mute-stream "0.0.7"
-    run-async "^2.2.0"
-    rx-lite "^4.0.8"
-    rx-lite-aggregates "^4.0.8"
-    string-width "^2.1.0"
-    strip-ansi "^4.0.0"
-    through "^2.3.6"
-
-interpret@^1.0.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
-  integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+interpret@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+  integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
 
-invariant@^2.2.2:
+invariant@^2.2.2, invariant@^2.2.4:
   version "2.2.4"
   resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
   integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
   dependencies:
     loose-envify "^1.0.0"
 
-invert-kv@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
-  integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
-
-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-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"
@@ -2951,6 +3077,24 @@ is-accessor-descriptor@^1.0.0:
   dependencies:
     kind-of "^6.0.0"
 
+is-alphabetical@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d"
+  integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==
+
+is-alphanumeric@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4"
+  integrity sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=
+
+is-alphanumerical@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf"
+  integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==
+  dependencies:
+    is-alphabetical "^1.0.0"
+    is-decimal "^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"
@@ -2963,15 +3107,27 @@ is-binary-path@^1.0.0:
   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-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:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
-  integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
+is-buffer@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623"
+  integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==
+
+is-callable@^1.1.4, is-callable@^1.2.0:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
+  integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==
 
 is-data-descriptor@^0.1.4:
   version "0.1.4"
@@ -2988,9 +3144,14 @@ is-data-descriptor@^1.0.0:
     kind-of "^6.0.0"
 
 is-date-object@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
-  integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e"
+  integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==
+
+is-decimal@^1.0.0, is-decimal@^1.0.2:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5"
+  integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==
 
 is-descriptor@^0.1.0:
   version "0.1.6"
@@ -3027,25 +3188,16 @@ is-extglob@^2.1.0, is-extglob@^2.1.1:
   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
   integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
 
-is-finite@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
-  integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
-  dependencies:
-    number-is-nan "^1.0.0"
-
-is-fullwidth-code-point@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
-  integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
-  dependencies:
-    number-is-nan "^1.0.0"
-
 is-fullwidth-code-point@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
   integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
 
+is-fullwidth-code-point@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+  integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
 is-glob@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
@@ -3053,28 +3205,22 @@ is-glob@^3.1.0:
   dependencies:
     is-extglob "^2.1.0"
 
-is-glob@^4.0.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-my-ip-valid@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
-  integrity sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==
-
-is-my-json-valid@^2.10.0:
-  version "2.20.0"
-  resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz#1345a6fca3e8daefc10d0fa77067f54cedafd59a"
-  integrity sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==
-  dependencies:
-    generate-function "^2.0.0"
-    generate-object-property "^1.1.0"
-    is-my-ip-valid "^1.0.0"
-    jsonpointer "^4.0.0"
-    xtend "^4.0.0"
+is-hexadecimal@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7"
+  integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==
+
+is-negative-zero@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461"
+  integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=
 
 is-number@^3.0.0:
   version "3.0.0"
@@ -3083,74 +3229,77 @@ is-number@^3.0.0:
   dependencies:
     kind-of "^3.0.2"
 
-is-plain-obj@^1.0.0:
+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-plain-obj@^1.0.0, is-plain-obj@^1.1.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.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+is-plain-obj@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+  integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
+
+is-plain-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-promise@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
-  integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
-
-is-property@^1.0.0, is-property@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
-  integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=
-
-is-regex@^1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
-  integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
+is-regex@^1.1.0, is-regex@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9"
+  integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==
   dependencies:
-    has "^1.0.1"
-
-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=
+    has-symbols "^1.0.1"
 
-is-svg@^2.0.0:
+is-regexp@^2.0.0:
   version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
-  integrity sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=
-  dependencies:
-    html-comment-regex "^1.1.0"
+  resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d"
+  integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==
+
+is-string@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
+  integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
 
 is-symbol@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
-  integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
+  integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==
   dependencies:
-    has-symbols "^1.0.0"
+    has-symbols "^1.0.1"
 
-is-typedarray@~1.0.0:
+is-typedarray@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
 
-is-utf8@^0.2.0:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
-  integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+is-whitespace-character@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7"
+  integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==
 
-is-windows@^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-word-character@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230"
+  integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==
+
+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"
@@ -3173,99 +3322,58 @@ isobject@^3.0.0, isobject@^3.0.1:
   resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
   integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
 
-isstream@~0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
-  integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
-
-js-base64@^2.1.8, js-base64@^2.1.9:
-  version "2.5.1"
-  resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
-  integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
+jest-worker@^26.3.0:
+  version "26.3.0"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.3.0.tgz#7c8a97e4f4364b4f05ed8bca8ca0c24de091871f"
+  integrity sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==
+  dependencies:
+    "@types/node" "*"
+    merge-stream "^2.0.0"
+    supports-color "^7.0.0"
 
-"js-tokens@^3.0.0 || ^4.0.0":
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
   integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
 
-js-tokens@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
-  integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls=
-
-js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4, js-yaml@^3.9.1:
-  version "3.13.1"
-  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
-  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+js-yaml@^3.13.1:
+  version "3.14.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482"
+  integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==
   dependencies:
     argparse "^1.0.7"
     esprima "^4.0.0"
 
-js-yaml@~3.7.0:
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
-  integrity sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=
-  dependencies:
-    argparse "^1.0.7"
-    esprima "^2.6.0"
-
-jsbn@~0.1.0:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
-  integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
-
-jsesc@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b"
-  integrity sha1-RsP+yMGJKxKwgz25vHYiF226s0s=
+jsesc@^2.5.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-loader@^0.5.4:
-  version "0.5.7"
-  resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.7.tgz#dca14a70235ff82f0ac9a3abeb60d337a365185d"
-  integrity sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==
+json-parse-better-errors@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
 
-json-schema-traverse@^0.3.0:
-  version "0.3.1"
-  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
-  integrity sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=
+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==
 
-json-schema@0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
-  integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
-
 json-stable-stringify-without-jsonify@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
   integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
 
-json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af"
-  integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=
-  dependencies:
-    jsonify "~0.0.0"
-
-json-stringify-safe@~5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
-  integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
-
-json5@^0.5.1:
-  version "0.5.1"
-  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
-  integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
-
 json5@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
@@ -3273,32 +3381,12 @@ json5@^1.0.1:
   dependencies:
     minimist "^1.2.0"
 
-jsonfile@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66"
-  integrity sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=
-  optionalDependencies:
-    graceful-fs "^4.1.6"
-
-jsonify@~0.0.0:
-  version "0.0.0"
-  resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
-  integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=
-
-jsonpointer@^4.0.0:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9"
-  integrity sha1-T9kss04OnbPInIYi7PUfm5eMbLk=
-
-jsprim@^1.2.2:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
-  integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+json5@^2.1.2:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43"
+  integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==
   dependencies:
-    assert-plus "1.0.0"
-    extsprintf "1.3.0"
-    json-schema "0.2.3"
-    verror "1.10.0"
+    minimist "^1.2.5"
 
 kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
   version "3.2.2"
@@ -3319,46 +3407,45 @@ kind-of@^5.0.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.2"
-  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
-  integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
+kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3:
+  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==
 
-known-css-properties@^0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.3.0.tgz#a3d135bbfc60ee8c6eacf2f7e7e6f2d4755e49a4"
-  integrity sha512-QMQcnKAiQccfQTqtBh/qwquGZ2XK/DXND1jrcN9M8gMMy99Gwla7GQjndVUsEqIaRyP6bsFRuhwRj5poafBGJQ==
+klona@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
+  integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
 
-lazy-cache@^1.0.3:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
-  integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
+known-css-properties@^0.19.0:
+  version "0.19.0"
+  resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.19.0.tgz#5d92b7fa16c72d971bda9b7fe295bdf61836ee5b"
+  integrity sha512-eYboRV94Vco725nKMlpkn3nV2+96p9c3gKXRsYqAJSswSENvBhN7n5L+uDhY58xQa0UukWsDMTGELzmD8Q+wTA==
 
-lcid@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
-  integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
-  dependencies:
-    invert-kv "^1.0.0"
+leven@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+  integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
 
-levn@^0.3.0, levn@~0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
-  integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
+levenary@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77"
+  integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==
   dependencies:
-    prelude-ls "~1.1.2"
-    type-check "~0.3.2"
+    leven "^3.1.0"
 
-load-json-file@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
-  integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+levn@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+  integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
   dependencies:
-    graceful-fs "^4.1.2"
-    parse-json "^2.2.0"
-    pify "^2.0.0"
-    pinkie-promise "^2.0.0"
-    strip-bom "^2.0.0"
+    prelude-ls "^1.2.1"
+    type-check "~0.4.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=
 
 load-json-file@^2.0.0:
   version "2.0.0"
@@ -3370,20 +3457,29 @@ load-json-file@^2.0.0:
     pify "^2.0.0"
     strip-bom "^3.0.0"
 
-loader-runner@^2.3.0:
+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.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
-  integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
+loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
+  integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
   dependencies:
     big.js "^5.2.2"
-    emojis-list "^2.0.0"
+    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@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -3392,55 +3488,37 @@ locate-path@^2.0.0:
     p-locate "^2.0.0"
     path-exists "^3.0.0"
 
-lodash.camelcase@^4.3.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
-  integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
-
-lodash.capitalize@^4.1.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9"
-  integrity sha1-+CbJtOKoUR2E46yinbBeGk87cqk=
-
-lodash.isplainobject@^4.0.6:
-  version "4.0.6"
-  resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
-  integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
-
-lodash.kebabcase@^4.0.0:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
-  integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
-
-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.some@^4.6.0:
-  version "4.6.0"
-  resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
-  integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=
+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"
 
-lodash.tail@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
-  integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
+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.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.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20:
+  version "4.17.20"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
+  integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
 
-lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.3.0, lodash@~4.17.10:
-  version "4.17.19"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
-  integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
+log-symbols@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920"
+  integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==
+  dependencies:
+    chalk "^4.0.0"
 
-longest@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
-  integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
+longest-streak@^2.0.1:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4"
+  integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==
 
 loose-envify@^1.0.0:
   version "1.4.0"
@@ -3449,39 +3527,50 @@ loose-envify@^1.0.0:
   dependencies:
     js-tokens "^3.0.0 || ^4.0.0"
 
-loud-rejection@^1.0.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
-  integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+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:
-    currently-unhandled "^0.4.1"
-    signal-exit "^3.0.0"
+    yallist "^3.0.2"
 
-lru-cache@^4.0.1:
-  version "4.1.5"
-  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
-  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+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:
-    pseudomap "^1.0.2"
-    yallist "^2.1.2"
+    yallist "^4.0.0"
 
-make-dir@^1.0.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
-  integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
+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:
+  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:
-    pify "^3.0.0"
+    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-obj@^1.0.0, map-obj@^1.0.1:
+map-obj@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
   integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
 
+map-obj@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5"
+  integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==
+
 map-visit@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
@@ -3489,10 +3578,22 @@ map-visit@^1.0.0:
   dependencies:
     object-visit "^1.0.0"
 
-math-expression-evaluator@^1.2.14:
-  version "1.2.17"
-  resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac"
-  integrity sha1-3oGf282E3M2PrlnGrreWFbnSZqw=
+markdown-escapes@^1.0.0:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535"
+  integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==
+
+markdown-table@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b"
+  integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==
+  dependencies:
+    repeat-string "^1.0.0"
+
+mathml-tag-names@^2.1.3:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3"
+  integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==
 
 md5.js@^1.3.4:
   version "1.3.5"
@@ -3503,14 +3604,14 @@ md5.js@^1.3.4:
     inherits "^2.0.1"
     safe-buffer "^5.1.2"
 
-mem@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76"
-  integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=
+mdast-util-compact@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz#cabc69a2f43103628326f35b1acf735d55c99490"
+  integrity sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==
   dependencies:
-    mimic-fn "^1.0.0"
+    unist-util-visit "^2.0.0"
 
-memory-fs@^0.4.0, memory-fs@~0.4.1:
+memory-fs@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
   integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
@@ -3518,28 +3619,42 @@ memory-fs@^0.4.0, memory-fs@~0.4.1:
     errno "^0.1.3"
     readable-stream "^2.0.1"
 
-meow@^3.7.0:
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
-  integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
-  dependencies:
-    camelcase-keys "^2.0.0"
-    decamelize "^1.1.2"
-    loud-rejection "^1.0.0"
-    map-obj "^1.0.1"
-    minimist "^1.1.3"
-    normalize-package-data "^2.3.4"
-    object-assign "^4.0.1"
-    read-pkg-up "^1.0.1"
-    redent "^1.0.0"
-    trim-newlines "^1.0.0"
+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@^1.2.0:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145"
-  integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ==
+meow@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-7.1.1.tgz#7c01595e3d337fcb0ec4e8eed1666ea95903d306"
+  integrity sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==
+  dependencies:
+    "@types/minimist" "^1.2.0"
+    camelcase-keys "^6.2.2"
+    decamelize-keys "^1.1.0"
+    hard-rejection "^2.1.0"
+    minimist-options "4.1.0"
+    normalize-package-data "^2.5.0"
+    read-pkg-up "^7.0.1"
+    redent "^3.0.0"
+    trim-newlines "^3.0.0"
+    type-fest "^0.13.1"
+    yargs-parser "^18.1.3"
+
+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==
 
-micromatch@^3.1.10, micromatch@^3.1.4:
+merge2@^1.3.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+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==
@@ -3558,6 +3673,14 @@ micromatch@^3.1.10, micromatch@^3.1.4:
     snapdragon "^0.8.1"
     to-regex "^3.0.2"
 
+micromatch@^4.0.2:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
+  integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
+  dependencies:
+    braces "^3.0.1"
+    picomatch "^2.0.5"
+
 miller-rabin@^4.0.0:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
@@ -3566,27 +3689,20 @@ miller-rabin@^4.0.0:
     bn.js "^4.0.0"
     brorand "^1.0.1"
 
-mime-db@1.40.0:
-  version "1.40.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
-  integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
+min-indent@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
+  integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
 
-mime-types@^2.1.12, mime-types@~2.1.19:
-  version "2.1.24"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
-  integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+mini-css-extract-plugin@^0.11.2:
+  version "0.11.2"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.11.2.tgz#e3af4d5e04fbcaaf11838ab230510073060b37bf"
+  integrity sha512-h2LknfX4U1kScXxH8xE9LCOqT5B+068EAj36qicMb8l4dqdJoyHcmWmpd+ueyZfgu/POvIn+teoUnTtei2ikug==
   dependencies:
-    mime-db "1.40.0"
-
-mime@^1.4.1:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
-  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-
-mimic-fn@^1.0.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
-  integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+    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"
@@ -3598,42 +3714,78 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^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.2, minimatch@^3.0.4, minimatch@~3.0.2:
+minimatch@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
   integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
   dependencies:
     brace-expansion "^1.1.7"
 
-minimist@0.0.8:
-  version "0.0.8"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
-  integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+minimist-options@4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
+  integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
+  dependencies:
+    arrify "^1.0.1"
+    is-plain-obj "^1.1.0"
+    kind-of "^6.0.3"
 
-minimist@1.1.x:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
-  integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag=
+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==
 
-minimist@^1.1.3, minimist@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
-  integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+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@^2.2.1, minipass@^2.3.4:
-  version "2.3.5"
-  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
-  integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+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:
-    safe-buffer "^5.1.2"
-    yallist "^3.0.0"
+    minipass "^3.0.0"
 
-minizlib@^1.1.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
-  integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
+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 "^2.2.1"
+    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"
@@ -3643,45 +3795,44 @@ mixin-deep@^1.2.0:
     for-in "^1.0.2"
     is-extendable "^1.0.1"
 
-mixin-object@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
-  integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
+mkdirp@^0.5.1, mkdirp@^0.5.3:
+  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:
-    for-in "^0.1.3"
-    is-extendable "^0.1.1"
+    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==
 
-"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
-  version "0.5.1"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
-  integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+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:
-    minimist "0.0.8"
+    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==
-
-mute-stream@0.0.5:
-  version "0.0.5"
-  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
-  integrity sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=
-
-mute-stream@0.0.7:
-  version "0.0.7"
-  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
-  integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+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==
 
-nan@^2.12.1, nan@^2.13.2:
-  version "2.14.0"
-  resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
-  integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+nan@^2.12.1:
+  version "2.14.1"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
+  integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
 
 nanomatch@^1.2.9:
   version "1.2.13"
@@ -3705,47 +3856,20 @@ natural-compare@^1.4.0:
   resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
   integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
 
-needle@^2.2.1:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
-  integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
-  dependencies:
-    debug "^3.2.6"
-    iconv-lite "^0.4.4"
-    sax "^1.2.4"
-
-neo-async@^2.5.0:
-  version "2.6.1"
-  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
-  integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
+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==
 
-next-tick@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
-  integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+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-gyp@^3.8.0:
-  version "3.8.0"
-  resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
-  integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
-  dependencies:
-    fstream "^1.0.0"
-    glob "^7.0.3"
-    graceful-fs "^4.1.2"
-    mkdirp "^0.5.0"
-    nopt "2 || 3"
-    npmlog "0 || 1 || 2 || 3 || 4"
-    osenv "0"
-    request "^2.87.0"
-    rimraf "2"
-    semver "~5.3.0"
-    tar "^2.0.0"
-    which "1"
-
-node-libs-browser@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.0.tgz#c72f60d9d46de08a940dedbb25f3ffa2f9bbaa77"
-  integrity sha512-5MQunG/oyOaBdttrL40dA7bUfPORLRWMUJLQtMg7nluxUvk5XwnLdL9twQHFAjRx/y7mIMkLKT9++qPbbk6BZA==
+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"
@@ -3757,7 +3881,7 @@ node-libs-browser@^2.0.0:
     events "^3.0.0"
     https-browserify "^1.0.0"
     os-browserify "^0.3.0"
-    path-browserify "0.0.0"
+    path-browserify "0.0.1"
     process "^0.11.10"
     punycode "^1.2.4"
     querystring-es3 "^0.2.0"
@@ -3769,63 +3893,14 @@ node-libs-browser@^2.0.0:
     tty-browserify "0.0.0"
     url "^0.11.0"
     util "^0.11.0"
-    vm-browserify "0.0.4"
+    vm-browserify "^1.0.1"
 
-node-pre-gyp@^0.12.0:
-  version "0.12.0"
-  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
-  integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
-  dependencies:
-    detect-libc "^1.0.2"
-    mkdirp "^0.5.1"
-    needle "^2.2.1"
-    nopt "^4.0.1"
-    npm-packlist "^1.1.6"
-    npmlog "^4.0.2"
-    rc "^1.2.7"
-    rimraf "^2.6.1"
-    semver "^5.3.0"
-    tar "^4"
-
-node-sass@^4.12.0:
-  version "4.12.0"
-  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
-  integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
-  dependencies:
-    async-foreach "^0.1.3"
-    chalk "^1.1.1"
-    cross-spawn "^3.0.0"
-    gaze "^1.0.0"
-    get-stdin "^4.0.1"
-    glob "^7.0.3"
-    in-publish "^2.0.0"
-    lodash "^4.17.11"
-    meow "^3.7.0"
-    mkdirp "^0.5.1"
-    nan "^2.13.2"
-    node-gyp "^3.8.0"
-    npmlog "^4.0.0"
-    request "^2.88.0"
-    sass-graph "^2.2.4"
-    stdout-stream "^1.4.0"
-    "true-case-path" "^1.0.2"
-
-"nopt@2 || 3":
-  version "3.0.6"
-  resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
-  integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
-  dependencies:
-    abbrev "1"
-
-nopt@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
-  integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
-  dependencies:
-    abbrev "1"
-    osenv "^0.1.4"
+node-releases@^1.1.61:
+  version "1.1.61"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.61.tgz#707b0fca9ce4e11783612ba4a2fcba09047af16e"
+  integrity sha512-DD5vebQLg8jLCOzwupn954fbIiZht05DAZs0k2u8NStSe6h9XdsuIQL8hSRKYiU8WUQRznmSDrKGbv3ObOmC7g==
 
-normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
   version "2.5.0"
   resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
   integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -3842,7 +3917,7 @@ normalize-path@^2.1.1:
   dependencies:
     remove-trailing-separator "^1.0.1"
 
-normalize-path@^3.0.0:
+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==
@@ -3852,7 +3927,12 @@ normalize-range@^0.1.2:
   resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
   integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
 
-normalize-url@^1.4.0:
+normalize-selector@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03"
+  integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=
+
+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=
@@ -3862,51 +3942,11 @@ normalize-url@^1.4.0:
     query-string "^4.1.0"
     sort-keys "^1.0.0"
 
-npm-bundled@^1.0.1:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
-  integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
-
-npm-packlist@^1.1.6:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.1.tgz#19064cdf988da80ea3cee45533879d90192bbfbc"
-  integrity sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==
-  dependencies:
-    ignore-walk "^3.0.1"
-    npm-bundled "^1.0.1"
-
-npm-run-path@^2.0.0:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
-  integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
-  dependencies:
-    path-key "^2.0.0"
-
-"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
-  integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
-  dependencies:
-    are-we-there-yet "~1.1.2"
-    console-control-strings "~1.1.0"
-    gauge "~2.7.3"
-    set-blocking "~2.0.0"
-
 num2fraction@^1.2.2:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede"
   integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=
 
-number-is-nan@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
-  integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
-
-oauth-sign@~0.9.0:
-  version "0.9.0"
-  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
-  integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
-
 object-assign@^4.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"
@@ -3921,7 +3961,12 @@ object-copy@^0.1.0:
     define-property "^0.2.5"
     kind-of "^3.0.3"
 
-object-keys@^1.0.12:
+object-inspect@^1.7.0, object-inspect@^1.8.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0"
+  integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==
+
+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==
@@ -3933,6 +3978,25 @@ object-visit@^1.0.0:
   dependencies:
     isobject "^3.0.0"
 
+object.assign@^4.1.0:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.1.tgz#303867a666cdd41936ecdedfb1f8f3e32a478cdd"
+  integrity sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.18.0-next.0"
+    has-symbols "^1.0.1"
+    object-keys "^1.1.1"
+
+object.entries@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.2.tgz#bc73f00acb6b6bb16c203434b10f9a7e797d3add"
+  integrity sha512-BQdB9qKmb/HyNdMNWVr7O3+z5MUIx3aiegEIJqjMBbBf0YT9RRxTJSim4mzFqtyr7PDAHigq0N9dO0m0tRakQA==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+    has "^1.0.3"
+
 object.pick@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -3940,81 +4004,40 @@ object.pick@^1.3.0:
   dependencies:
     isobject "^3.0.1"
 
-once@^1.3.0:
+object.values@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e"
+  integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.0-next.1"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
   integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
   dependencies:
     wrappy "1"
 
-onetime@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
-  integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=
-
-onetime@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
-  integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
-  dependencies:
-    mimic-fn "^1.0.0"
-
-optionator@^0.8.1, optionator@^0.8.2:
-  version "0.8.2"
-  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
-  integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
+optionator@^0.9.1:
+  version "0.9.1"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499"
+  integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==
   dependencies:
-    deep-is "~0.1.3"
-    fast-levenshtein "~2.0.4"
-    levn "~0.3.0"
-    prelude-ls "~1.1.2"
-    type-check "~0.3.2"
-    wordwrap "~1.0.0"
+    deep-is "^0.1.3"
+    fast-levenshtein "^2.0.6"
+    levn "^0.4.1"
+    prelude-ls "^1.2.1"
+    type-check "^0.4.0"
+    word-wrap "^1.2.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=
 
-os-homedir@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
-  integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
-
-os-locale@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
-  integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
-  dependencies:
-    lcid "^1.0.0"
-
-os-locale@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2"
-  integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==
-  dependencies:
-    execa "^0.7.0"
-    lcid "^1.0.0"
-    mem "^1.1.0"
-
-os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
-  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
-
-osenv@0, osenv@^0.1.4:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
-  integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
-  dependencies:
-    os-homedir "^1.0.0"
-    os-tmpdir "^1.0.0"
-
-p-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@^1.1.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@@ -4022,35 +4045,102 @@ p-limit@^1.1.0:
   dependencies:
     p-try "^1.0.0"
 
+p-limit@^2.0.0, p-limit@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+  dependencies:
+    p-try "^2.0.0"
+
+p-limit@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.0.2.tgz#1664e010af3cadc681baafd3e2a437be7b0fb5fe"
+  integrity sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==
+  dependencies:
+    p-try "^2.0.0"
+
 p-locate@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
   integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
   dependencies:
-    p-limit "^1.1.0"
+    p-limit "^1.1.0"
+
+p-locate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+  integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+  dependencies:
+    p-limit "^2.0.0"
+
+p-locate@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+  integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+  dependencies:
+    p-limit "^2.2.0"
+
+p-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-try@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
   integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
 
+p-try@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
 pako@~1.0.5:
-  version "1.0.10"
-  resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
-  integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
+  integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
+
+parallel-transform@^1.1.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc"
+  integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==
+  dependencies:
+    cyclist "^1.0.1"
+    inherits "^2.0.3"
+    readable-stream "^2.1.5"
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
 
-parse-asn1@^5.0.0:
-  version "5.1.4"
-  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc"
-  integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==
+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 "^4.0.0"
+    asn1.js "^5.2.0"
     browserify-aes "^1.0.0"
-    create-hash "^1.1.0"
     evp_bytestokey "^1.0.0"
     pbkdf2 "^3.0.3"
     safe-buffer "^5.1.1"
 
+parse-entities@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8"
+  integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==
+  dependencies:
+    character-entities "^1.0.0"
+    character-entities-legacy "^1.0.0"
+    character-reference-invalid "^1.0.0"
+    is-alphanumerical "^1.0.0"
+    is-decimal "^1.0.0"
+    is-hexadecimal "^1.0.0"
+
 parse-json@^2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
@@ -4058,62 +4148,66 @@ parse-json@^2.2.0:
   dependencies:
     error-ex "^1.2.0"
 
+parse-json@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
+  integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==
+  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=
+
 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.0:
-  version "0.0.0"
-  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
-  integrity sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=
+path-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
+  integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
 
 path-dirname@^1.0.0:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
   integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
 
-path-exists@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
-  integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
-  dependencies:
-    pinkie-promise "^2.0.0"
-
 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-is-absolute@^1.0.0, path-is-absolute@^1.0.1:
+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.1, path-is-inside@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
-  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
-
-path-key@^2.0.0:
+path-key@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
   integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
 
+path-key@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
 path-parse@^1.0.6:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
   integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
 
-path-type@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
-  integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
-  dependencies:
-    graceful-fs "^4.1.2"
-    pify "^2.0.0"
-    pinkie-promise "^2.0.0"
-
 path-type@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
@@ -4121,10 +4215,15 @@ path-type@^2.0.0:
   dependencies:
     pify "^2.0.0"
 
+path-type@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
 pbkdf2@^3.0.3:
-  version "3.0.17"
-  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
-  integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94"
+  integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==
   dependencies:
     create-hash "^1.1.2"
     create-hmac "^1.1.4"
@@ -4132,32 +4231,20 @@ pbkdf2@^3.0.3:
     safe-buffer "^5.0.1"
     sha.js "^2.4.8"
 
-performance-now@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
-  integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
+  integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
 
 pify@^2.0.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
   integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
 
-pify@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
-  integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
-
-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=
+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==
 
 pkg-dir@^2.0.0:
   version "2.0.0"
@@ -4166,350 +4253,168 @@ pkg-dir@^2.0.0:
   dependencies:
     find-up "^2.1.0"
 
-pluralize@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45"
-  integrity sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=
+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"
 
-pluralize@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777"
-  integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==
+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"
 
 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-calc@^5.2.0:
-  version "5.3.1"
-  resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e"
-  integrity sha1-d7rnypKK2FcW4v2kLyYb98HWW14=
-  dependencies:
-    postcss "^5.0.2"
-    postcss-message-helpers "^2.0.0"
-    reduce-css-calc "^1.2.6"
-
-postcss-colormin@^2.1.8:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b"
-  integrity sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=
-  dependencies:
-    colormin "^1.0.5"
-    postcss "^5.0.13"
-    postcss-value-parser "^3.2.3"
-
-postcss-convert-values@^2.3.4:
-  version "2.6.1"
-  resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d"
-  integrity sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=
-  dependencies:
-    postcss "^5.0.11"
-    postcss-value-parser "^3.1.2"
-
-postcss-discard-comments@^2.0.4:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d"
-  integrity sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=
-  dependencies:
-    postcss "^5.0.14"
-
-postcss-discard-duplicates@^2.0.1:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932"
-  integrity sha1-uavye4isGIFYpesSq8riAmO5GTI=
-  dependencies:
-    postcss "^5.0.4"
-
-postcss-discard-empty@^2.0.1:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5"
-  integrity sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=
-  dependencies:
-    postcss "^5.0.14"
-
-postcss-discard-overridden@^0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58"
-  integrity sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=
-  dependencies:
-    postcss "^5.0.16"
-
-postcss-discard-unused@^2.2.1:
-  version "2.2.3"
-  resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433"
-  integrity sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=
-  dependencies:
-    postcss "^5.0.14"
-    uniqs "^2.0.0"
-
-postcss-filter-plugins@^2.0.0:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz#82245fdf82337041645e477114d8e593aa18b8ec"
-  integrity sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==
-  dependencies:
-    postcss "^5.0.4"
-
-postcss-merge-idents@^2.1.5:
-  version "2.1.7"
-  resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270"
-  integrity sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=
+postcss-html@^0.36.0:
+  version "0.36.0"
+  resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204"
+  integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw==
   dependencies:
-    has "^1.0.1"
-    postcss "^5.0.10"
-    postcss-value-parser "^3.1.1"
+    htmlparser2 "^3.10.0"
 
-postcss-merge-longhand@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658"
-  integrity sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=
+postcss-less@^3.1.4:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad"
+  integrity sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA==
   dependencies:
-    postcss "^5.0.4"
+    postcss "^7.0.14"
 
-postcss-merge-rules@^2.0.3:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721"
-  integrity sha1-0d9d+qexrMO+VT8OnhDofGG19yE=
-  dependencies:
-    browserslist "^1.5.2"
-    caniuse-api "^1.5.2"
-    postcss "^5.0.4"
-    postcss-selector-parser "^2.2.2"
-    vendors "^1.0.0"
+postcss-media-query-parser@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244"
+  integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=
 
-postcss-message-helpers@^2.0.0:
+postcss-modules-extract-imports@^2.0.0:
   version "2.0.0"
-  resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e"
-  integrity sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=
-
-postcss-minify-font-values@^1.0.2:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69"
-  integrity sha1-S1jttWZB66fIR0qzUmyv17vey2k=
-  dependencies:
-    object-assign "^4.0.1"
-    postcss "^5.0.4"
-    postcss-value-parser "^3.0.2"
-
-postcss-minify-gradients@^1.0.1:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1"
-  integrity sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=
-  dependencies:
-    postcss "^5.0.12"
-    postcss-value-parser "^3.3.0"
-
-postcss-minify-params@^1.0.4:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3"
-  integrity sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=
-  dependencies:
-    alphanum-sort "^1.0.1"
-    postcss "^5.0.2"
-    postcss-value-parser "^3.0.2"
-    uniqs "^2.0.0"
-
-postcss-minify-selectors@^2.0.4:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf"
-  integrity sha1-ssapjAByz5G5MtGkllCBFDEXNb8=
-  dependencies:
-    alphanum-sort "^1.0.2"
-    has "^1.0.1"
-    postcss "^5.0.14"
-    postcss-selector-parser "^2.0.0"
-
-postcss-modules-extract-imports@^1.2.0:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz#dc87e34148ec7eab5f791f7cd5849833375b741a"
-  integrity sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==
-  dependencies:
-    postcss "^6.0.1"
-
-postcss-modules-local-by-default@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069"
-  integrity sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=
-  dependencies:
-    css-selector-tokenizer "^0.7.0"
-    postcss "^6.0.1"
-
-postcss-modules-scope@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90"
-  integrity sha1-1upkmUx5+XtipytCb75gVqGUu5A=
+  resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
+  integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==
   dependencies:
-    css-selector-tokenizer "^0.7.0"
-    postcss "^6.0.1"
+    postcss "^7.0.5"
 
-postcss-modules-values@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20"
-  integrity sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=
+postcss-modules-local-by-default@^3.0.3:
+  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-replace-symbols "^1.1.0"
-    postcss "^6.0.1"
+    icss-utils "^4.1.1"
+    postcss "^7.0.32"
+    postcss-selector-parser "^6.0.2"
+    postcss-value-parser "^4.1.0"
 
-postcss-normalize-charset@^1.1.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1"
-  integrity sha1-757nEhLX/nWceO0WL2HtYrXLk/E=
+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 "^5.0.5"
+    postcss "^7.0.6"
+    postcss-selector-parser "^6.0.0"
 
-postcss-normalize-url@^3.0.7:
-  version "3.0.8"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222"
-  integrity sha1-EI90s/L82viRov+j6kWSJ5/HgiI=
+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:
-    is-absolute-url "^2.0.0"
-    normalize-url "^1.4.0"
-    postcss "^5.0.14"
-    postcss-value-parser "^3.2.3"
+    icss-utils "^4.0.0"
+    postcss "^7.0.6"
 
-postcss-ordered-values@^2.1.0:
-  version "2.2.3"
-  resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d"
-  integrity sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=
-  dependencies:
-    postcss "^5.0.4"
-    postcss-value-parser "^3.0.1"
+postcss-resolve-nested-selector@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e"
+  integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=
 
-postcss-reduce-idents@^2.2.2:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3"
-  integrity sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=
+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 "^5.0.4"
-    postcss-value-parser "^3.0.2"
+    postcss "^7.0.26"
 
-postcss-reduce-initial@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea"
-  integrity sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=
+postcss-sass@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.4.4.tgz#91f0f3447b45ce373227a98b61f8d8f0785285a3"
+  integrity sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg==
   dependencies:
-    postcss "^5.0.4"
+    gonzales-pe "^4.3.0"
+    postcss "^7.0.21"
 
-postcss-reduce-transforms@^1.0.3:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1"
-  integrity sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=
+postcss-scss@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.1.1.tgz#ec3a75fa29a55e016b90bf3269026c53c1d2b383"
+  integrity sha512-jQmGnj0hSGLd9RscFw9LyuSVAa5Bl1/KBPqG1NQw9w8ND55nY4ZEsdlVuYJvLPpV+y0nwTV5v/4rHPzZRihQbA==
   dependencies:
-    has "^1.0.1"
-    postcss "^5.0.8"
-    postcss-value-parser "^3.0.1"
+    postcss "^7.0.6"
 
-postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.2.2:
-  version "2.2.3"
-  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90"
-  integrity sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=
+postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.3.tgz#766d77728728817cc140fa1ac6da5e77f9fada98"
+  integrity sha512-0ClFaY4X1ra21LRqbW6y3rUbWcxnSVkDFG57R7Nxus9J9myPFlv+jYDMohzpkBx0RrjjiqjtycpchQ+PLGmZ9w==
   dependencies:
-    flatten "^1.0.2"
+    cssesc "^3.0.0"
     indexes-of "^1.0.1"
     uniq "^1.0.1"
+    util-deprecate "^1.0.2"
 
-postcss-svgo@^2.1.1:
-  version "2.1.6"
-  resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d"
-  integrity sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=
-  dependencies:
-    is-svg "^2.0.0"
-    postcss "^5.0.14"
-    postcss-value-parser "^3.2.3"
-    svgo "^0.7.0"
-
-postcss-unique-selectors@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d"
-  integrity sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=
-  dependencies:
-    alphanum-sort "^1.0.1"
-    postcss "^5.0.4"
-    uniqs "^2.0.0"
-
-postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0:
-  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-zindex@^2.0.1:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22"
-  integrity sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=
-  dependencies:
-    has "^1.0.1"
-    postcss "^5.0.4"
-    uniqs "^2.0.0"
+postcss-syntax@^0.36.2:
+  version "0.36.2"
+  resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c"
+  integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==
 
-postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.2, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.16:
-  version "5.2.18"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5"
-  integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==
-  dependencies:
-    chalk "^1.1.3"
-    js-base64 "^2.1.9"
-    source-map "^0.5.6"
-    supports-color "^3.2.3"
+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@^6.0.1:
-  version "6.0.23"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324"
-  integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==
+postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.32, postcss@^7.0.5, postcss@^7.0.6:
+  version "7.0.34"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.34.tgz#f2baf57c36010df7de4009940f21532c16d65c20"
+  integrity sha512-H/7V2VeNScX9KE83GDrDZNiGT1m2H+UTnlinIzhjlLX9hfMUn1mHNnGeX81a1c8JSBdBvqk7c2ZOG6ZPn5itGw==
   dependencies:
-    chalk "^2.4.1"
+    chalk "^2.4.2"
     source-map "^0.6.1"
-    supports-color "^5.4.0"
+    supports-color "^6.1.0"
 
-prelude-ls@~1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
-  integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+prelude-ls@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+  integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
 
 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=
 
-private@^0.1.6, private@^0.1.8:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
-  integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
-
 process-nextick-args@~2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
-  integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==
+  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=
 
-progress@^1.1.8:
-  version "1.1.8"
-  resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be"
-  integrity sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=
-
 progress@^2.0.0:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
   integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
 
+promise-inflight@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+  integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
+
 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=
 
-pseudomap@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
-  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
-
-psl@^1.1.24:
-  version "1.1.31"
-  resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184"
-  integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==
-
 public-encrypt@^4.0.0:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
@@ -4522,12 +4427,37 @@ public-encrypt@^4.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, punycode@^1.4.1:
+punycode@^1.2.4:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
   integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
@@ -4543,19 +4473,9 @@ pure-extras@^1.0.0:
   integrity sha1-N+PMNZDLqFCYFFTNpdso4npjhxo=
 
 purecss@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/purecss/-/purecss-1.0.0.tgz#3dbcd9e2a7592448a69acb705cce16311bf4b785"
-  integrity sha512-gfC78WCOWNnfkzulx9aoWwcl+0JflhwKeJ+k9s/ZyIawfYNA4bqBmt0DtfgtQK9iuYMtGfbdE8R2AQMjSWR2VQ==
-
-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.5.2:
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
-  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/purecss/-/purecss-1.0.1.tgz#c83d84326a10beb5c3b36d20c0254e946e5568a7"
+  integrity sha512-mTUc5ZzpzafswEhCmTDfSRMMyRFdLYdd+KywMwnBC/MuA/Th7jug2z0Xso4WkxvtxoU/BS9aRb7WnBNyuA7YJQ==
 
 query-string@^4.1.0:
   version "4.3.4"
@@ -4575,7 +4495,12 @@ querystring@0.2.0:
   resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
   integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
 
-randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
+quick-lru@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
+  integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
+
+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==
@@ -4590,24 +4515,6 @@ randomfill@^1.0.3:
     randombytes "^2.0.5"
     safe-buffer "^5.1.0"
 
-rc@^1.2.7:
-  version "1.2.8"
-  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
-  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
-  dependencies:
-    deep-extend "^0.6.0"
-    ini "~1.3.0"
-    minimist "^1.2.0"
-    strip-json-comments "~2.0.1"
-
-read-pkg-up@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"
-  integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
-  dependencies:
-    find-up "^1.0.0"
-    read-pkg "^1.0.0"
-
 read-pkg-up@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
@@ -4616,14 +4523,14 @@ read-pkg-up@^2.0.0:
     find-up "^2.0.0"
     read-pkg "^2.0.0"
 
-read-pkg@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28"
-  integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+read-pkg-up@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+  integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
   dependencies:
-    load-json-file "^1.0.0"
-    normalize-package-data "^2.3.2"
-    path-type "^1.0.0"
+    find-up "^4.1.0"
+    read-pkg "^5.2.0"
+    type-fest "^0.8.1"
 
 read-pkg@^2.0.0:
   version "2.0.0"
@@ -4634,10 +4541,20 @@ read-pkg@^2.0.0:
     normalize-package-data "^2.3.2"
     path-type "^2.0.0"
 
-readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6:
-  version "2.3.6"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
-  integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+read-pkg@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+  integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+  dependencies:
+    "@types/normalize-package-data" "^2.4.0"
+    normalize-package-data "^2.5.0"
+    parse-json "^5.0.0"
+    type-fest "^0.6.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"
@@ -4647,6 +4564,15 @@ readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable
     string_decoder "~1.1.1"
     util-deprecate "~1.0.1"
 
+readable-stream@^3.1.1, 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"
@@ -4656,57 +4582,44 @@ readdirp@^2.2.1:
     micromatch "^3.1.10"
     readable-stream "^2.0.2"
 
-readline2@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35"
-  integrity sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=
-  dependencies:
-    code-point-at "^1.0.0"
-    is-fullwidth-code-point "^1.0.0"
-    mute-stream "0.0.5"
-
-redent@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
-  integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+readdirp@~3.4.0:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada"
+  integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==
   dependencies:
-    indent-string "^2.1.0"
-    strip-indent "^1.0.1"
+    picomatch "^2.2.1"
 
-reduce-css-calc@^1.2.6:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
-  integrity sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=
+redent@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
+  integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
   dependencies:
-    balanced-match "^0.4.2"
-    math-expression-evaluator "^1.2.14"
-    reduce-function-call "^1.0.1"
+    indent-string "^4.0.0"
+    strip-indent "^3.0.0"
 
-reduce-function-call@^1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99"
-  integrity sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=
+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:
-    balanced-match "^0.4.2"
+    regenerate "^1.4.0"
 
-regenerate@^1.2.1:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
-  integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+regenerate@^1.4.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.1.tgz#cad92ad8e6b591773485fbe05a485caf4f457e6f"
+  integrity sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==
 
-regenerator-runtime@^0.11.0:
-  version "0.11.1"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
-  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+regenerator-runtime@^0.13.4:
+  version "0.13.7"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
+  integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
 
-regenerator-transform@^0.10.0:
-  version "0.10.1"
-  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"
-  integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==
+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 "^6.18.0"
-    babel-types "^6.19.0"
-    private "^0.1.6"
+    "@babel/runtime" "^7.8.4"
 
 regex-not@^1.0.0, regex-not@^1.0.2:
   version "1.0.2"
@@ -4716,41 +4629,86 @@ regex-not@^1.0.0, regex-not@^1.0.2:
     extend-shallow "^3.0.2"
     safe-regex "^1.1.0"
 
-regexpp@^1.0.1:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab"
-  integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==
-
-regexpu-core@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b"
-  integrity sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=
-  dependencies:
-    regenerate "^1.2.1"
-    regjsgen "^0.2.0"
-    regjsparser "^0.1.4"
-
-regexpu-core@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240"
-  integrity sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=
-  dependencies:
-    regenerate "^1.2.1"
-    regjsgen "^0.2.0"
-    regjsparser "^0.1.4"
-
-regjsgen@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7"
-  integrity sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=
+regexpp@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
+  integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
+
+regexpu-core@^4.7.0:
+  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.1.4:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c"
-  integrity sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=
+regjsparser@^0.6.4:
+  version "0.6.4"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272"
+  integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==
   dependencies:
     jsesc "~0.5.0"
 
+remark-parse@^8.0.0:
+  version "8.0.3"
+  resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.3.tgz#9c62aa3b35b79a486454c690472906075f40c7e1"
+  integrity sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==
+  dependencies:
+    ccount "^1.0.0"
+    collapse-white-space "^1.0.2"
+    is-alphabetical "^1.0.0"
+    is-decimal "^1.0.0"
+    is-whitespace-character "^1.0.0"
+    is-word-character "^1.0.0"
+    markdown-escapes "^1.0.0"
+    parse-entities "^2.0.0"
+    repeat-string "^1.5.4"
+    state-toggle "^1.0.0"
+    trim "0.0.1"
+    trim-trailing-lines "^1.0.0"
+    unherit "^1.0.4"
+    unist-util-remove-position "^2.0.0"
+    vfile-location "^3.0.0"
+    xtend "^4.0.1"
+
+remark-stringify@^8.0.0:
+  version "8.1.1"
+  resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-8.1.1.tgz#e2a9dc7a7bf44e46a155ec78996db896780d8ce5"
+  integrity sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A==
+  dependencies:
+    ccount "^1.0.0"
+    is-alphanumeric "^1.0.0"
+    is-decimal "^1.0.0"
+    is-whitespace-character "^1.0.0"
+    longest-streak "^2.0.1"
+    markdown-escapes "^1.0.0"
+    markdown-table "^2.0.0"
+    mdast-util-compact "^2.0.0"
+    parse-entities "^2.0.0"
+    repeat-string "^1.5.4"
+    state-toggle "^1.0.0"
+    stringify-entities "^3.0.0"
+    unherit "^1.0.4"
+    xtend "^4.0.1"
+
+remark@^12.0.0:
+  version "12.0.1"
+  resolved "https://registry.yarnpkg.com/remark/-/remark-12.0.1.tgz#f1ddf68db7be71ca2bad0a33cd3678b86b9c709f"
+  integrity sha512-gS7HDonkdIaHmmP/+shCPejCEEW+liMp/t/QwmF0Xt47Rpuhl32lLtDV1uKWvGoq+kxr5jSgg5oAIpGuyULjUw==
+  dependencies:
+    remark-parse "^8.0.0"
+    remark-stringify "^8.0.0"
+    unified "^9.0.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"
@@ -4761,114 +4719,99 @@ repeat-element@^1.1.2:
   resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
   integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
 
-repeat-string@^1.5.2, repeat-string@^1.6.1:
+repeat-string@^1.0.0, repeat-string@^1.5.4, repeat-string@^1.6.1:
   version "1.6.1"
   resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
   integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
 
-repeating@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
-  integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
-  dependencies:
-    is-finite "^1.0.0"
-
-request@^2.87.0, request@^2.88.0:
-  version "2.88.0"
-  resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
-  integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
-  dependencies:
-    aws-sign2 "~0.7.0"
-    aws4 "^1.8.0"
-    caseless "~0.12.0"
-    combined-stream "~1.0.6"
-    extend "~3.0.2"
-    forever-agent "~0.6.1"
-    form-data "~2.3.2"
-    har-validator "~5.1.0"
-    http-signature "~1.2.0"
-    is-typedarray "~1.0.0"
-    isstream "~0.1.2"
-    json-stringify-safe "~5.0.1"
-    mime-types "~2.1.19"
-    oauth-sign "~0.9.0"
-    performance-now "^2.1.0"
-    qs "~6.5.2"
-    safe-buffer "^5.1.2"
-    tough-cookie "~2.4.3"
-    tunnel-agent "^0.6.0"
-    uuid "^3.3.2"
+replace-ext@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
+  integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
 
 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@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
-  integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
+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==
 
-require-uncached@^1.0.2, require-uncached@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
-  integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=
+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:
-    caller-path "^0.1.0"
-    resolve-from "^1.0.0"
+    resolve-from "^3.0.0"
 
-resolve-from@^1.0.0:
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
   version "1.0.1"
-  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
-  integrity sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=
+  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-from@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+  integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
 
 resolve-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.10.0, resolve@^1.5.0:
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.0.tgz#4014870ba296176b86343d50b60f3b50609ce232"
-  integrity sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==
+resolve@^1.10.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2:
+  version "1.17.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
+  integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
   dependencies:
     path-parse "^1.0.6"
 
-restore-cursor@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
-  integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=
-  dependencies:
-    exit-hook "^1.0.0"
-    onetime "^1.0.0"
-
-restore-cursor@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
-  integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
-  dependencies:
-    onetime "^2.0.0"
-    signal-exit "^3.0.2"
-
 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==
 
-right-align@^0.1.1:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
-  integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
-  dependencies:
-    align-text "^0.1.1"
+reusify@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
-rimraf@2, rimraf@^2.6.1, rimraf@~2.6.2:
+rimraf@2.6.3:
   version "2.6.3"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
   integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
   dependencies:
     glob "^7.1.3"
 
+rimraf@^2.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"
@@ -4877,38 +4820,24 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
     hash-base "^3.0.0"
     inherits "^2.0.1"
 
-run-async@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
-  integrity sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=
-  dependencies:
-    once "^1.3.0"
-
-run-async@^2.2.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
-  integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
-  dependencies:
-    is-promise "^2.1.0"
+run-parallel@^1.1.9:
+  version "1.1.9"
+  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
+  integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
 
-rx-lite-aggregates@^4.0.8:
-  version "4.0.8"
-  resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
-  integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=
+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:
-    rx-lite "*"
+    aproba "^1.1.1"
 
-rx-lite@*, rx-lite@^4.0.8:
-  version "4.0.8"
-  resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
-  integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=
+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==
 
-rx-lite@^3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
-  integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=
-
-safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+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==
@@ -4920,63 +4849,28 @@ safe-regex@^1.1.0:
   dependencies:
     ret "~0.1.10"
 
-"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+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-graph@^2.2.4:
-  version "2.2.4"
-  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
-  integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=
-  dependencies:
-    glob "^7.0.0"
-    lodash "^4.0.0"
-    scss-tokenizer "^0.2.3"
-    yargs "^7.0.0"
-
-sass-lint@^1.12.1:
-  version "1.13.1"
-  resolved "https://registry.yarnpkg.com/sass-lint/-/sass-lint-1.13.1.tgz#5fd2b2792e9215272335eb0f0dc607f61e8acc8f"
-  integrity sha512-DSyah8/MyjzW2BWYmQWekYEKir44BpLqrCFsgs9iaWiVTcwZfwXHF586hh3D1n+/9ihUNMfd8iHAyb9KkGgs7Q==
-  dependencies:
-    commander "^2.8.1"
-    eslint "^2.7.0"
-    front-matter "2.1.2"
-    fs-extra "^3.0.1"
-    glob "^7.0.0"
-    globule "^1.0.0"
-    gonzales-pe-sl "^4.2.3"
-    js-yaml "^3.5.4"
-    known-css-properties "^0.3.0"
-    lodash.capitalize "^4.1.0"
-    lodash.kebabcase "^4.0.0"
-    merge "^1.2.0"
-    path-is-absolute "^1.0.0"
-    util "^0.10.3"
-
-sass-loader@^6.0.6:
-  version "6.0.7"
-  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.7.tgz#dd2fdb3e7eeff4a53f35ba6ac408715488353d00"
-  integrity sha512-JoiyD00Yo1o61OJsoP2s2kb19L1/Y2p3QFcCdWdF6oomBGKVYuZyqHWemRBfQ2uGYsk+CH3eCguXNfpjzlcpaA==
+sass-loader@^10.0.2:
+  version "10.0.2"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-10.0.2.tgz#c7b73010848b264792dd45372eea0b87cba4401e"
+  integrity sha512-wV6NDUVB8/iEYMalV/+139+vl2LaRFlZGEd5/xmdcdzQcgmis+npyco6NsDTVOlNA3y2NV9Gcz+vHyFMIT+ffg==
   dependencies:
-    clone-deep "^2.0.1"
-    loader-utils "^1.0.1"
-    lodash.tail "^4.1.1"
-    neo-async "^2.5.0"
-    pify "^3.0.0"
-
-sax@^1.2.4, sax@~1.2.1:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
-  integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+    klona "^2.0.3"
+    loader-utils "^2.0.0"
+    neo-async "^2.6.2"
+    schema-utils "^2.7.1"
+    semver "^7.3.2"
 
-schema-utils@^0.3.0:
-  version "0.3.0"
-  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-0.3.0.tgz#f5877222ce3e931edae039f17eb3716e7137f8cf"
-  integrity sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=
+sass@^1.26.11:
+  version "1.26.11"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.26.11.tgz#0f22cc4ab2ba27dad1d4ca30837beb350b709847"
+  integrity sha512-W1l/+vjGjIamsJ6OnTe0K37U2DBO/dgsv2Z4c89XQ8ZOO6l/VwkqwLSqoYzJeJs6CLuGSTRWc91GbQFL3lvrvw==
   dependencies:
-    ajv "^5.0.0"
+    chokidar ">=2.0.0 <4.0.0"
 
 schema-utils@^0.4.5:
   version "0.4.7"
@@ -4986,43 +4880,67 @@ schema-utils@^0.4.5:
     ajv "^6.1.0"
     ajv-keywords "^3.1.0"
 
-scss-tokenizer@^0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
-  integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE=
+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.1:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
+  integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==
   dependencies:
-    js-base64 "^2.1.8"
-    source-map "^0.4.2"
+    "@types/json-schema" "^7.0.5"
+    ajv "^6.12.4"
+    ajv-keywords "^3.5.2"
 
-"semver@2 || 3 || 4 || 5", semver@^5.3.0:
-  version "5.7.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
-  integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+"semver@2 || 3 || 4 || 5", semver@^5.4.1, 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@~5.3.0:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
-  integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
+semver@7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
+  integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
 
-set-blocking@^2.0.0, 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=
+semver@^6.0.0:
+  version "6.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
-set-value@^0.4.3:
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1"
-  integrity sha1-fbCPnT0i3H945Trzw79GZuzfzPE=
+semver@^7.2.1, semver@^7.3.2:
+  version "7.3.2"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
+  integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
+
+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:
-    extend-shallow "^2.0.1"
-    is-extendable "^0.1.1"
-    is-plain-object "^2.0.1"
-    to-object-path "^0.3.0"
+    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"
 
-set-value@^2.0.0:
+set-blocking@^2.0.0:
   version "2.0.0"
-  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274"
-  integrity sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==
+  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"
@@ -5042,15 +4960,6 @@ sha.js@^2.4.0, sha.js@^2.4.8:
     inherits "^2.0.1"
     safe-buffer "^5.0.1"
 
-shallow-clone@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
-  integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
-  dependencies:
-    is-extendable "^0.1.1"
-    kind-of "^5.0.0"
-    mixin-object "^2.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"
@@ -5058,38 +4967,51 @@ shebang-command@^1.2.0:
   dependencies:
     shebang-regex "^1.0.0"
 
+shebang-command@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+  dependencies:
+    shebang-regex "^3.0.0"
+
 shebang-regex@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
   integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
 
-shelljs@^0.6.0:
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8"
-  integrity sha1-7GIRvtGSBEIIj+D3Cyg3Iy7SyKg=
-
-signal-exit@^3.0.0, signal-exit@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
-  integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+shebang-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
 
-slash@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
-  integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=
+signal-exit@^3.0.2:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
+  integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
 
-slice-ansi@0.0.4:
-  version "0.0.4"
-  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
-  integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=
+slash@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+  integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
 
-slice-ansi@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d"
-  integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==
+slice-ansi@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+  integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
   dependencies:
+    ansi-styles "^3.2.0"
+    astral-regex "^1.0.0"
     is-fullwidth-code-point "^2.0.0"
 
+slice-ansi@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b"
+  integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==
+  dependencies:
+    ansi-styles "^4.0.0"
+    astral-regex "^2.0.0"
+    is-fullwidth-code-point "^3.0.0"
+
 snapdragon-node@^2.0.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@@ -5133,70 +5055,69 @@ source-list-map@^2.0.0:
   integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
 
 source-map-resolve@^0.5.0:
-  version "0.5.2"
-  resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
-  integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
+  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.1"
+    atob "^2.1.2"
     decode-uri-component "^0.2.0"
     resolve-url "^0.2.1"
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
-source-map-support@^0.4.15:
-  version "0.4.18"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f"
-  integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==
+source-map-support@~0.5.12:
+  version "0.5.19"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
+  integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
   dependencies:
-    source-map "^0.5.6"
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
 
 source-map-url@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
   integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
 
-source-map@^0.4.2:
-  version "0.4.4"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
-  integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
-  dependencies:
-    amdefine ">=0.0.4"
-
-source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1:
+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.1, source-map@~0.6.1:
+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==
 
 spdx-correct@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
-  integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9"
+  integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==
   dependencies:
     spdx-expression-parse "^3.0.0"
     spdx-license-ids "^3.0.0"
 
 spdx-exceptions@^2.1.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
-  integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d"
+  integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==
 
 spdx-expression-parse@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
-  integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+  integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
   dependencies:
     spdx-exceptions "^2.1.0"
     spdx-license-ids "^3.0.0"
 
 spdx-license-ids@^3.0.0:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz#75ecd1a88de8c184ef015eafb51b5b48bfd11bb1"
-  integrity sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce"
+  integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==
+
+specificity@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019"
+  integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg==
 
 split-string@^3.0.1, split-string@^3.0.2:
   version "3.1.0"
@@ -5210,20 +5131,24 @@ sprintf-js@~1.0.2:
   resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
   integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
 
-sshpk@^1.7.0:
-  version "1.16.1"
-  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
-  integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
-  dependencies:
-    asn1 "~0.2.3"
-    assert-plus "^1.0.0"
-    bcrypt-pbkdf "^1.0.0"
-    dashdash "^1.12.0"
-    ecc-jsbn "~0.1.1"
-    getpass "^0.1.1"
-    jsbn "~0.1.0"
-    safer-buffer "^2.0.2"
-    tweetnacl "~0.14.0"
+ssri@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
+  integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
+  dependencies:
+    figgy-pudding "^3.5.1"
+
+ssri@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808"
+  integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==
+  dependencies:
+    minipass "^3.1.1"
+
+state-toggle@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe"
+  integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==
 
 static-extend@^0.1.1:
   version "0.1.2"
@@ -5233,13 +5158,6 @@ static-extend@^0.1.1:
     define-property "^0.2.5"
     object-copy "^0.1.0"
 
-stdout-stream@^1.4.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
-  integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==
-  dependencies:
-    readable-stream "^2.0.1"
-
 stream-browserify@^2.0.1:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
@@ -5248,6 +5166,14 @@ stream-browserify@^2.0.1:
     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"
@@ -5259,34 +5185,56 @@ stream-http@^2.7.2:
     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@^1.0.1, string-width@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3"
-  integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+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:
-    code-point-at "^1.0.0"
-    is-fullwidth-code-point "^1.0.0"
-    strip-ansi "^3.0.0"
+    emoji-regex "^7.0.1"
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^5.1.0"
 
-"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
-  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+string-width@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
+  integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
   dependencies:
-    is-fullwidth-code-point "^2.0.0"
-    strip-ansi "^4.0.0"
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.0"
 
-string_decoder@^1.0.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
-  integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
+string.prototype.trimend@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913"
+  integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==
   dependencies:
-    safe-buffer "~5.1.0"
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+
+string.prototype.trimstart@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54"
+  integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==
+  dependencies:
+    define-properties "^1.1.3"
+    es-abstract "^1.17.5"
+
+string_decoder@^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"
@@ -5295,185 +5243,277 @@ string_decoder@~1.1.1:
   dependencies:
     safe-buffer "~5.1.0"
 
-strip-ansi@^3.0.0, strip-ansi@^3.0.1:
+stringify-entities@^3.0.0:
   version "3.0.1"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
-  integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+  resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-3.0.1.tgz#32154b91286ab0869ab2c07696223bd23b6dbfc0"
+  integrity sha512-Lsk3ISA2++eJYqBMPKcr/8eby1I6L0gP0NlxF8Zja6c05yr/yCYyb2c9PwXjd08Ib3If1vn1rbs1H5ZtVuOfvQ==
   dependencies:
-    ansi-regex "^2.0.0"
+    character-entities-html4 "^1.0.0"
+    character-entities-legacy "^1.0.0"
+    is-alphanumerical "^1.0.0"
+    is-decimal "^1.0.2"
+    is-hexadecimal "^1.0.0"
 
-strip-ansi@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
-  integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+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 "^3.0.0"
+    ansi-regex "^4.1.0"
 
-strip-bom@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
-  integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+strip-ansi@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
+  integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
   dependencies:
-    is-utf8 "^0.2.0"
+    ansi-regex "^5.0.0"
 
 strip-bom@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
   integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
 
-strip-eof@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
-  integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-
-strip-indent@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
-  integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+strip-indent@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
+  integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
   dependencies:
-    get-stdin "^4.0.1"
-
-strip-json-comments@~1.0.1:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91"
-  integrity sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=
+    min-indent "^1.0.0"
 
-strip-json-comments@~2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
-  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+  integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
 
-style-loader@^0.19.1:
-  version "0.19.1"
-  resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.19.1.tgz#591ffc80bcefe268b77c5d9ebc0505d772619f85"
-  integrity sha512-IRE+ijgojrygQi3rsqT0U4dd+UcPCqcVvauZpCnQrGAlEe+FUIyrK93bUDScamesjP08JlQNsFJU+KmPedP5Og==
-  dependencies:
-    loader-utils "^1.0.2"
-    schema-utils "^0.3.0"
+style-search@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
+  integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=
 
-supports-color@^2.0.0:
+stylelint-config-recommended@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-3.0.0.tgz#e0e547434016c5539fe2650afd58049a2fd1d657"
+  integrity sha512-F6yTRuc06xr1h5Qw/ykb2LuFynJ2IxkKfCMf+1xqPffkxh0S09Zc902XCffcsw/XMFq/OzQ1w54fLIDtmRNHnQ==
+
+stylelint-config-standard@^20.0.0:
+  version "20.0.0"
+  resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-20.0.0.tgz#06135090c9e064befee3d594289f50e295b5e20d"
+  integrity sha512-IB2iFdzOTA/zS4jSVav6z+wGtin08qfj+YyExHB3LF9lnouQht//YyB0KZq9gGz5HNPkddHOzcY8HsUey6ZUlA==
+  dependencies:
+    stylelint-config-recommended "^3.0.0"
+
+stylelint-scss@^3.18.0:
+  version "3.18.0"
+  resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.18.0.tgz#8f06371c223909bf3f62e839548af1badeed31e9"
+  integrity sha512-LD7+hv/6/ApNGt7+nR/50ft7cezKP2HM5rI8avIdGaUWre3xlHfV4jKO/DRZhscfuN+Ewy9FMhcTq0CcS0C/SA==
+  dependencies:
+    lodash "^4.17.15"
+    postcss-media-query-parser "^0.2.3"
+    postcss-resolve-nested-selector "^0.1.1"
+    postcss-selector-parser "^6.0.2"
+    postcss-value-parser "^4.1.0"
+
+stylelint@^13.7.1:
+  version "13.7.1"
+  resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.7.1.tgz#bee97ee78d778a3f1dbe3f7397b76414973e263e"
+  integrity sha512-qzqazcyRxrSRdmFuO0/SZOJ+LyCxYy0pwcvaOBBnl8/2VfHSMrtNIE+AnyJoyq6uKb+mt+hlgmVrvVi6G6XHfQ==
+  dependencies:
+    "@stylelint/postcss-css-in-js" "^0.37.2"
+    "@stylelint/postcss-markdown" "^0.36.1"
+    autoprefixer "^9.8.6"
+    balanced-match "^1.0.0"
+    chalk "^4.1.0"
+    cosmiconfig "^7.0.0"
+    debug "^4.1.1"
+    execall "^2.0.0"
+    fast-glob "^3.2.4"
+    fastest-levenshtein "^1.0.12"
+    file-entry-cache "^5.0.1"
+    get-stdin "^8.0.0"
+    global-modules "^2.0.0"
+    globby "^11.0.1"
+    globjoin "^0.1.4"
+    html-tags "^3.1.0"
+    ignore "^5.1.8"
+    import-lazy "^4.0.0"
+    imurmurhash "^0.1.4"
+    known-css-properties "^0.19.0"
+    lodash "^4.17.20"
+    log-symbols "^4.0.0"
+    mathml-tag-names "^2.1.3"
+    meow "^7.1.1"
+    micromatch "^4.0.2"
+    normalize-selector "^0.2.0"
+    postcss "^7.0.32"
+    postcss-html "^0.36.0"
+    postcss-less "^3.1.4"
+    postcss-media-query-parser "^0.2.3"
+    postcss-resolve-nested-selector "^0.1.1"
+    postcss-safe-parser "^4.0.2"
+    postcss-sass "^0.4.4"
+    postcss-scss "^2.1.1"
+    postcss-selector-parser "^6.0.2"
+    postcss-syntax "^0.36.2"
+    postcss-value-parser "^4.1.0"
+    resolve-from "^5.0.0"
+    slash "^3.0.0"
+    specificity "^0.4.1"
+    string-width "^4.2.0"
+    strip-ansi "^6.0.0"
+    style-search "^0.1.0"
+    sugarss "^2.0.0"
+    svg-tags "^1.0.0"
+    table "^6.0.1"
+    v8-compile-cache "^2.1.1"
+    write-file-atomic "^3.0.3"
+
+sugarss@^2.0.0:
   version "2.0.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
-  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
-
-supports-color@^3.2.3:
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6"
-  integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=
-  dependencies:
-    has-flag "^1.0.0"
-
-supports-color@^4.2.1:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
-  integrity sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=
+  resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d"
+  integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ==
   dependencies:
-    has-flag "^2.0.0"
+    postcss "^7.0.2"
 
-supports-color@^5.3.0, supports-color@^5.4.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"
 
-svgo@^0.7.0:
-  version "0.7.2"
-  resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
-  integrity sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=
+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:
-    coa "~1.0.1"
-    colors "~1.1.2"
-    csso "~2.3.1"
-    js-yaml "~3.7.0"
-    mkdirp "~0.5.1"
-    sax "~1.2.1"
-    whet.extend "~0.9.9"
+    has-flag "^3.0.0"
 
-table@4.0.2:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36"
-  integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==
-  dependencies:
-    ajv "^5.2.3"
-    ajv-keywords "^2.1.0"
-    chalk "^2.1.0"
-    lodash "^4.17.4"
-    slice-ansi "1.0.0"
-    string-width "^2.1.1"
-
-table@^3.7.8:
-  version "3.8.3"
-  resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f"
-  integrity sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=
-  dependencies:
-    ajv "^4.7.0"
-    ajv-keywords "^1.0.0"
-    chalk "^1.1.1"
-    lodash "^4.0.0"
-    slice-ansi "0.0.4"
-    string-width "^2.0.0"
-
-tapable@^0.2.7:
-  version "0.2.9"
-  resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.9.tgz#af2d8bbc9b04f74ee17af2b4d9048f807acd18a8"
-  integrity sha512-2wsvQ+4GwBvLPLWsNfLCDYGsW6xb7aeC6utq2Qh0PFwgEy7K7dsma9Jsmb2zSQj7GvYAyUGSntLtsv++GmgL1A==
-
-tar@^2.0.0:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
-  integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==
+supports-color@^7.0.0, supports-color@^7.1.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:
-    block-stream "*"
-    fstream "^1.0.12"
-    inherits "2"
+    has-flag "^4.0.0"
 
-tar@^4:
-  version "4.4.8"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
-  integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==
+svg-tags@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
+  integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
+
+table@^5.2.3:
+  version "5.4.6"
+  resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
+  integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
+  dependencies:
+    ajv "^6.10.2"
+    lodash "^4.17.14"
+    slice-ansi "^2.1.0"
+    string-width "^3.0.0"
+
+table@^6.0.1:
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/table/-/table-6.0.3.tgz#e5b8a834e37e27ad06de2e0fda42b55cfd8a0123"
+  integrity sha512-8321ZMcf1B9HvVX/btKv8mMZahCjn2aYrDlpqHaBFCfnox64edeH9kEid0vTLTRR8gWR2A20aDgeuTTea4sVtw==
+  dependencies:
+    ajv "^6.12.4"
+    lodash "^4.17.20"
+    slice-ansi "^4.0.0"
+    string-width "^4.2.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.0.5"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-6.0.5.tgz#bde815086e10b39f1dcd298e89d596e1535e200f"
+  integrity sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==
+  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.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-4.2.2.tgz#d86200c700053bba637913fe4310ba1bdeb5568e"
+  integrity sha512-3qAQpykRTD5DReLu5/cwpsg7EZFzP3Q0Hp2XUWJUw2mpq2jfgOKTZr8IZKKnNieRVVo1UauROTdhbQJZveGKtQ==
+  dependencies:
+    cacache "^15.0.5"
+    find-cache-dir "^3.3.1"
+    jest-worker "^26.3.0"
+    p-limit "^3.0.2"
+    schema-utils "^2.7.1"
+    serialize-javascript "^5.0.1"
+    source-map "^0.6.1"
+    terser "^5.3.2"
+    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:
-    chownr "^1.1.1"
-    fs-minipass "^1.2.5"
-    minipass "^2.3.4"
-    minizlib "^1.1.1"
-    mkdirp "^0.5.0"
-    safe-buffer "^5.1.2"
-    yallist "^3.0.2"
+    commander "^2.20.0"
+    source-map "~0.6.1"
+    source-map-support "~0.5.12"
+
+terser@^5.3.2:
+  version "5.3.2"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.3.2.tgz#f4bea90eb92945b2a028ceef79181b9bb586e7af"
+  integrity sha512-H67sydwBz5jCUA32ZRL319ULu+Su1cAoZnnc+lXnenGRYWyLE3Scgkt8mNoAsMx0h5kdo758zdoS0LG9rYZXDQ==
+  dependencies:
+    commander "^2.20.0"
+    source-map "~0.6.1"
+    source-map-support "~0.5.12"
 
-text-table@~0.2.0:
+text-table@^0.2.0:
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
   integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
 
-through@^2.3.6:
-  version "2.3.8"
-  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
-  integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+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"
 
 timers-browserify@^2.0.4:
-  version "2.0.10"
-  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae"
-  integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==
+  version "2.0.11"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
+  integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==
   dependencies:
     setimmediate "^1.0.4"
 
-tmp@^0.0.33:
-  version "0.0.33"
-  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
-  integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
-  dependencies:
-    os-tmpdir "~1.0.2"
-
 to-arraybuffer@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
   integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
 
-to-fast-properties@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
-  integrity sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
 
 to-object-path@^0.3.0:
   version "0.3.0"
@@ -5490,6 +5530,13 @@ to-regex-range@^2.1.0:
     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"
@@ -5500,108 +5547,194 @@ to-regex@^3.0.1, to-regex@^3.0.2:
     regex-not "^1.0.2"
     safe-regex "^1.1.0"
 
-tough-cookie@~2.4.3:
-  version "2.4.3"
-  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
-  integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
-  dependencies:
-    psl "^1.1.24"
-    punycode "^1.4.1"
+trim-newlines@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30"
+  integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==
 
-trim-newlines@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
-  integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+trim-trailing-lines@^1.0.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94"
+  integrity sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==
 
-trim-right@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
-  integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
+trim@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
+  integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0=
 
-"true-case-path@^1.0.2":
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
-  integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==
+trough@^1.0.0:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
+  integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==
+
+tsconfig-paths@^3.9.0:
+  version "3.9.0"
+  resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b"
+  integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==
   dependencies:
-    glob "^7.1.2"
+    "@types/json5" "^0.0.29"
+    json5 "^1.0.1"
+    minimist "^1.2.0"
+    strip-bom "^3.0.0"
+
+tslib@^1.9.0:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
+  integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
 
 tty-browserify@0.0.0:
   version "0.0.0"
   resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
   integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
 
-tunnel-agent@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
-  integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
+type-check@^0.4.0, type-check@~0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+  integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
   dependencies:
-    safe-buffer "^5.0.1"
+    prelude-ls "^1.2.1"
 
-tweetnacl@^0.14.3, tweetnacl@~0.14.0:
-  version "0.14.5"
-  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
-  integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+type-fest@^0.13.1:
+  version "0.13.1"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934"
+  integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==
 
-type-check@~0.3.2:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
-  integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+type-fest@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+  integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
+type-fest@^0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+  integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
+typedarray-to-buffer@^3.1.5:
+  version "3.1.5"
+  resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+  integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
   dependencies:
-    prelude-ls "~1.1.2"
+    is-typedarray "^1.0.0"
 
 typedarray@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
 
-uglify-js@^2.8.29:
-  version "2.8.29"
-  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
-  integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
+unherit@^1.0.4:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22"
+  integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==
   dependencies:
-    source-map "~0.5.1"
-    yargs "~3.10.0"
-  optionalDependencies:
-    uglify-to-browserify "~1.0.0"
+    inherits "^2.0.0"
+    xtend "^4.0.0"
 
-uglify-to-browserify@~1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
-  integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
+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==
 
-uglifyjs-webpack-plugin@^0.4.6:
-  version "0.4.6"
-  resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309"
-  integrity sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=
+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:
-    source-map "^0.5.6"
-    uglify-js "^2.8.29"
-    webpack-sources "^1.0.1"
+    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==
+
+unified@^9.0.0:
+  version "9.2.0"
+  resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.0.tgz#67a62c627c40589edebbf60f53edfd4d822027f8"
+  integrity sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==
+  dependencies:
+    bail "^1.0.0"
+    extend "^3.0.0"
+    is-buffer "^2.0.0"
+    is-plain-obj "^2.0.0"
+    trough "^1.0.0"
+    vfile "^4.0.0"
 
 union-value@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"
-  integrity sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=
+  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 "^0.4.3"
+    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"
 
-universalify@^0.1.0:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
-  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+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"
+
+unist-util-find-all-after@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-3.0.1.tgz#95cc62f48812d879b4685a0512bf1b838da50e9a"
+  integrity sha512-0GICgc++sRJesLwEYDjFVJPJttBpVQaTNgc6Jw0Jhzvfs+jtKePEMu+uD+PqkRUrAvGQqwhpDwLGWo1PK8PDEw==
+  dependencies:
+    unist-util-is "^4.0.0"
+
+unist-util-is@^4.0.0:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.0.2.tgz#c7d1341188aa9ce5b3cff538958de9895f14a5de"
+  integrity sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==
+
+unist-util-remove-position@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc"
+  integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==
+  dependencies:
+    unist-util-visit "^2.0.0"
+
+unist-util-stringify-position@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da"
+  integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==
+  dependencies:
+    "@types/unist" "^2.0.2"
+
+unist-util-visit-parents@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.0.tgz#4dd262fb9dcfe44f297d53e882fc6ff3421173d5"
+  integrity sha512-0g4wbluTF93npyPrp/ymd3tCDTMnP0yo2akFD2FIBAYXq/Sga3lwaU1D8OYKbtpioaI6CkDcQ6fsMnmtzt7htw==
+  dependencies:
+    "@types/unist" "^2.0.0"
+    unist-util-is "^4.0.0"
+
+unist-util-visit@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.3.tgz#c3703893146df47203bb8a9795af47d7b971208c"
+  integrity sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==
+  dependencies:
+    "@types/unist" "^2.0.0"
+    unist-util-is "^4.0.0"
+    unist-util-visit-parents "^3.0.0"
 
 unset-value@^1.0.0:
   version "1.0.0"
@@ -5612,14 +5745,14 @@ unset-value@^1.0.0:
     isobject "^3.0.0"
 
 upath@^1.1.1:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
-  integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
+  integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
 
 uri-js@^4.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
-  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602"
+  integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==
   dependencies:
     punycode "^2.1.0"
 
@@ -5628,15 +5761,6 @@ urix@^0.1.0:
   resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
   integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
 
-url-loader@^0.6.2:
-  version "0.6.2"
-  resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.6.2.tgz#a007a7109620e9d988d14bce677a1decb9a993f7"
-  integrity sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==
-  dependencies:
-    loader-utils "^1.0.2"
-    mime "^1.4.1"
-    schema-utils "^0.3.0"
-
 url@^0.11.0:
   version "0.11.0"
   resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
@@ -5650,14 +5774,7 @@ use@^3.1.0:
   resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
   integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
 
-user-home@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f"
-  integrity sha1-nHC/2Babwdy/SGBODwS4tJzenp8=
-  dependencies:
-    os-homedir "^1.0.0"
-
-util-deprecate@~1.0.1:
+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=
@@ -5669,13 +5786,6 @@ util@0.10.3:
   dependencies:
     inherits "2.0.1"
 
-util@^0.10.3:
-  version "0.10.4"
-  resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
-  integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
-  dependencies:
-    inherits "2.0.3"
-
 util@^0.11.0:
   version "0.11.1"
   resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
@@ -5683,10 +5793,10 @@ util@^0.11.0:
   dependencies:
     inherits "2.0.3"
 
-uuid@^3.3.2:
-  version "3.3.2"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
-  integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
+  integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
 
 validate-npm-package-license@^3.0.1:
   version "3.0.4"
@@ -5696,214 +5806,222 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
-vendors@^1.0.0:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.3.tgz#a6467781abd366217c050f8202e7e50cc9eef8c0"
-  integrity sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==
+vfile-location@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.1.0.tgz#81cd8a04b0ac935185f4fce16f270503fc2f692f"
+  integrity sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g==
 
-verror@1.10.0:
-  version "1.10.0"
-  resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
-  integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+vfile-message@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
+  integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==
   dependencies:
-    assert-plus "^1.0.0"
-    core-util-is "1.0.2"
-    extsprintf "^1.2.0"
+    "@types/unist" "^2.0.0"
+    unist-util-stringify-position "^2.0.0"
+
+vfile@^4.0.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.0.tgz#26c78ac92eb70816b01d4565e003b7e65a2a0e01"
+  integrity sha512-a/alcwCvtuc8OX92rqqo7PflxiCgXRFjdyoGVuYV+qbgCb0GgZJRvIgCD4+U/Kl1yhaRsaTwksF88xbPyGsgpw==
+  dependencies:
+    "@types/unist" "^2.0.0"
+    is-buffer "^2.0.0"
+    replace-ext "1.0.0"
+    unist-util-stringify-position "^2.0.0"
+    vfile-message "^2.0.0"
+
+vm-browserify@^1.0.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
+  integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
 
-vm-browserify@0.0.4:
-  version "0.0.4"
-  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73"
-  integrity sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=
+watchpack-chokidar2@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
+  integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==
   dependencies:
-    indexof "0.0.1"
+    chokidar "^2.1.8"
 
-watchpack@^1.4.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
-  integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==
+watchpack@^1.7.4:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.4.tgz#6e9da53b3c80bb2d6508188f5b200410866cd30b"
+  integrity sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==
   dependencies:
-    chokidar "^2.0.2"
     graceful-fs "^4.1.2"
     neo-async "^2.5.0"
-
-webpack-sources@^1.0.1:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
-  integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==
+  optionalDependencies:
+    chokidar "^3.4.1"
+    watchpack-chokidar2 "^2.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-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@^3.10.0:
-  version "3.12.0"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.12.0.tgz#3f9e34360370602fcf639e97939db486f4ec0d74"
-  integrity sha512-Sw7MdIIOv/nkzPzee4o0EdvCuPmxT98+vVpIvwtcwcF1Q4SDSNp92vwcKc4REe7NItH9f1S4ra9FuQ7yuYZ8bQ==
-  dependencies:
-    acorn "^5.0.0"
-    acorn-dynamic-import "^2.0.0"
-    ajv "^6.1.0"
-    ajv-keywords "^3.1.0"
-    async "^2.1.2"
-    enhanced-resolve "^3.4.0"
-    escope "^3.6.0"
-    interpret "^1.0.0"
-    json-loader "^0.5.4"
-    json5 "^0.5.1"
-    loader-runner "^2.3.0"
-    loader-utils "^1.1.0"
-    memory-fs "~0.4.1"
-    mkdirp "~0.5.0"
-    node-libs-browser "^2.0.0"
-    source-map "^0.5.3"
-    supports-color "^4.2.1"
-    tapable "^0.2.7"
-    uglifyjs-webpack-plugin "^0.4.6"
-    watchpack "^1.4.0"
-    webpack-sources "^1.0.1"
-    yargs "^8.0.2"
-
-whet.extend@~0.9.9:
-  version "0.9.9"
-  resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1"
-  integrity sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=
-
-which-module@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
-  integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
+webpack@^4.44.2:
+  version "4.44.2"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.44.2.tgz#6bfe2b0af055c8b2d1e90ed2cd9363f841266b72"
+  integrity sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==
+  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.3.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"
 
 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, which@^1.2.9:
+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"
 
-wide-align@^1.1.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
-  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+which@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
   dependencies:
-    string-width "^1.0.2 || 2"
-
-window-size@0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
-  integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
+    isexe "^2.0.0"
 
-wordwrap@0.0.2:
-  version "0.0.2"
-  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
-  integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
+word-wrap@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+  integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
 
-wordwrap@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
-  integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
+worker-farm@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
+  integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
+  dependencies:
+    errno "~0.1.7"
 
-wrap-ansi@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
-  integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
+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:
-    string-width "^1.0.1"
-    strip-ansi "^3.0.1"
+    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=
 
-write@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
-  integrity sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=
+write-file-atomic@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+  integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
+  dependencies:
+    imurmurhash "^0.1.4"
+    is-typedarray "^1.0.0"
+    signal-exit "^3.0.2"
+    typedarray-to-buffer "^3.1.5"
+
+write@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+  integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
   dependencies:
     mkdirp "^0.5.1"
 
-xtend@^4.0.0:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
-  integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68=
+xtend@^4.0.0, xtend@^4.0.1, 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@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
-  integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
+y18n@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
+  integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
 
-yallist@^2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
-  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+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@^3.0.0, yallist@^3.0.2:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
-  integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
+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==
 
-yargs-parser@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
-  integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
+yaml@^1.10.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
+  integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==
+
+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 "^3.0.0"
+    camelcase "^5.0.0"
+    decamelize "^1.2.0"
 
-yargs-parser@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
-  integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k=
-  dependencies:
-    camelcase "^4.1.0"
-
-yargs@^7.0.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
-  integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
-  dependencies:
-    camelcase "^3.0.0"
-    cliui "^3.2.0"
-    decamelize "^1.1.1"
-    get-caller-file "^1.0.1"
-    os-locale "^1.4.0"
-    read-pkg-up "^1.0.1"
-    require-directory "^2.1.1"
-    require-main-filename "^1.0.1"
-    set-blocking "^2.0.0"
-    string-width "^1.0.2"
-    which-module "^1.0.0"
-    y18n "^3.2.1"
-    yargs-parser "^5.0.0"
-
-yargs@^8.0.2:
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360"
-  integrity sha1-YpmpBVsc78lp/355wdkY3Osiw2A=
-  dependencies:
-    camelcase "^4.1.0"
-    cliui "^3.2.0"
-    decamelize "^1.1.1"
-    get-caller-file "^1.0.1"
-    os-locale "^2.0.0"
-    read-pkg-up "^2.0.0"
+yargs-parser@^18.1.3:
+  version "18.1.3"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
+  integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
+  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 "^1.0.1"
+    require-main-filename "^2.0.0"
     set-blocking "^2.0.0"
-    string-width "^2.0.0"
+    string-width "^3.0.0"
     which-module "^2.0.0"
-    y18n "^3.2.1"
-    yargs-parser "^7.0.0"
-
-yargs@~3.10.0:
-  version "3.10.0"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
-  integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
-  dependencies:
-    camelcase "^1.0.2"
-    cliui "^2.1.0"
-    decamelize "^1.0.0"
-    window-size "0.1.0"
+    y18n "^4.0.0"
+    yargs-parser "^13.1.2"