diff --git a/Dockerfile b/Dockerfile
index d4003c49463ab25b9fba48260f64e8118823b004..a2123509c1c7fa36cc4d8734c60fb7cbe6a3d9a0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -10,8 +10,12 @@ WORKDIR /castopod
 RUN apt-get update && apt-get install -y \
     libicu-dev \
     libpng-dev \
+    libjpeg-dev \
     zlib1g-dev \
-    && docker-php-ext-install intl gd
+    && docker-php-ext-install intl
+
+RUN docker-php-ext-configure gd --with-jpeg-dir=/usr/include/ \
+    && docker-php-ext-install gd
 
 RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
 
@@ -19,4 +23,5 @@ RUN echo "file_uploads = On\n" \
          "memory_limit = 100M\n" \
          "upload_max_filesize = 100M\n" \
          "post_max_size = 120M\n" \
+         "max_execution_time = 300\n" \
          > /usr/local/etc/php/conf.d/uploads.ini
diff --git a/app/Config/Images.php b/app/Config/Images.php
index e5632dbc07a69233c3ab90bca0ebf3a31ccc41de..bcbaa83a6540261a93970b99898a574821fee360 100644
--- a/app/Config/Images.php
+++ b/app/Config/Images.php
@@ -30,4 +30,73 @@ class Images extends BaseConfig
         'gd' => \CodeIgniter\Images\Handlers\GDHandler::class,
         'imagick' => \CodeIgniter\Images\Handlers\ImageMagickHandler::class,
     ];
+
+    /**
+     * --------------------------------------------------------------------------
+     * Uploaded images resizing sizes (in px)
+     * --------------------------------------------------------------------------
+     * The sizes listed below determine the resizing of images when uploaded.
+     * All uploaded images are of 1:1 ratio (width and height are the same).
+     */
+
+    /**
+     * @var integer
+     */
+    public $thumbnailSize = 150;
+
+    /**
+     * @var integer
+     */
+    public $mediumSize = 320;
+
+    /**
+     * @var integer
+     */
+    public $largeSize = 1024;
+
+    /**
+     * Size of images linked in the rss feed (should be between 1400 and 3000)
+     *
+     * @var integer
+     */
+    public $feedSize = 1400;
+
+    /**
+     * Size for ID3 tag cover art (should be between 300 and 800)
+     *
+     * @var integer
+     */
+    public $id3Size = 500;
+
+    /**
+     * --------------------------------------------------------------------------
+     * Uploaded images naming extensions
+     * --------------------------------------------------------------------------
+     * The properties listed below set the name extensions for the resized images
+     */
+
+    /**
+     * @var string
+     */
+    public $thumbnailExtension = '_thumbnail';
+
+    /**
+     * @var string
+     */
+    public $mediumExtension = '_medium';
+
+    /**
+     * @var string
+     */
+    public $largeExtension = '_large';
+
+    /**
+     * @var string
+     */
+    public $feedExtension = '_feed';
+
+    /**
+     * @var string
+     */
+    public $id3Extension = '_id3';
 }
diff --git a/app/Config/Validation.php b/app/Config/Validation.php
index f27fefb992ed0eec4de0823d01f801d945390bbf..8ebd77c4850582e05ca25b2917c84f2c6740d21b 100644
--- a/app/Config/Validation.php
+++ b/app/Config/Validation.php
@@ -17,9 +17,9 @@ class Validation
     public $ruleSets = [
         \CodeIgniter\Validation\Rules::class,
         \CodeIgniter\Validation\FormatRules::class,
-        \CodeIgniter\Validation\FileRules::class,
         \CodeIgniter\Validation\CreditCardRules::class,
         \App\Validation\Rules::class,
+        \App\Validation\FileRules::class,
         \Myth\Auth\Authentication\Passwords\ValidationRules::class,
     ];
 
diff --git a/app/Controllers/Admin/Episode.php b/app/Controllers/Admin/Episode.php
index 1979e64f9a5da25a4afbcc2034b9b80ae96f9ff9..39ce2e0c0bacb87f4b8be4fccefbc4033aa96a83 100644
--- a/app/Controllers/Admin/Episode.php
+++ b/app/Controllers/Admin/Episode.php
@@ -85,7 +85,7 @@ class Episode extends BaseController
         $rules = [
             'enclosure' => 'uploaded[enclosure]|ext_in[enclosure,mp3,m4a]',
             'image' =>
-                'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|permit_empty',
+                'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
             'publication_date' => 'valid_date[Y-m-d]|permit_empty',
             'publication_time' =>
                 'regex_match[/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/]|permit_empty',
@@ -151,7 +151,7 @@ class Episode extends BaseController
             'enclosure' =>
                 'uploaded[enclosure]|ext_in[enclosure,mp3,m4a]|permit_empty',
             'image' =>
-                'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|permit_empty',
+                'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
             'publication_date' => 'valid_date[Y-m-d]|permit_empty',
             'publication_time' =>
                 'regex_match[/^(0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$/]|permit_empty',
diff --git a/app/Controllers/Admin/Podcast.php b/app/Controllers/Admin/Podcast.php
index f2a29ec59048872ec1e2f916af4e465ee6e0d9d7..ab0dde47dfeef6dfccfe1250c29e23c29665da46 100644
--- a/app/Controllers/Admin/Podcast.php
+++ b/app/Controllers/Admin/Podcast.php
@@ -79,7 +79,8 @@ class Podcast extends BaseController
     public function attemptCreate()
     {
         $rules = [
-            'image' => 'uploaded[image]|is_image[image]|ext_in[image,jpg,png]',
+            'image' =>
+                'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
         ];
 
         if (!$this->validate($rules)) {
@@ -162,8 +163,9 @@ class Podcast extends BaseController
         helper(['media', 'misc']);
 
         $rules = [
-            'name' => 'required',
-            'imported_feed_url' => 'required',
+            'imported_feed_url' => 'required|valid_url',
+            'season_number' => 'is_natural_no_zero|permit_empty',
+            'max_episodes' => 'is_natural_no_zero|permit_empty',
         ];
 
         if (!$this->validate($rules)) {
@@ -217,8 +219,6 @@ class Podcast extends BaseController
             'complete' => empty($nsItunes->complete)
                 ? false
                 : $nsItunes->complete == 'yes',
-            'episode_description_footer' => '',
-            'custom_html_head' => '',
             'created_by' => user(),
             'updated_by' => user(),
         ]);
@@ -299,9 +299,10 @@ class Podcast extends BaseController
                     ? null
                     : download_file($nsItunes->image->attributes()),
                 'explicit' => $nsItunes->explicit == 'yes',
-                'number' => $this->request->getPost('force_renumber')
-                    ? $itemNumber
-                    : $nsItunes->episode,
+                'number' =>
+                    $this->request->getPost('force_renumber') == 'yes'
+                        ? $itemNumber
+                        : $nsItunes->episode,
                 'season_number' => empty(
                     $this->request->getPost('season_number')
                 )
@@ -358,7 +359,7 @@ class Podcast extends BaseController
     {
         $rules = [
             'image' =>
-                'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|permit_empty',
+                'is_image[image]|ext_in[image,jpg,png]|min_dims[image,1400,1400]|is_image_squared[image]',
         ];
 
         if (!$this->validate($rules)) {
diff --git a/app/Controllers/Analytics.php b/app/Controllers/Analytics.php
index d9c82d31c1a12edbc07266d2e17a6edfd82e967b..ec89dc2260fed1fe3e8f901ef319fef9e101982f 100644
--- a/app/Controllers/Analytics.php
+++ b/app/Controllers/Analytics.php
@@ -47,6 +47,8 @@ class Analytics extends Controller
     // Add one hit to this episode:
     public function hit($p_podcastId, $p_episodeId, ...$filename)
     {
+        helper('media');
+
         podcast_hit($p_podcastId, $p_episodeId);
         return redirect()->to(media_url(implode('/', $filename)));
     }
diff --git a/app/Entities/Episode.php b/app/Entities/Episode.php
index 463c49605215273c6b1a4d2a881e848435835712..9c7311231a906d71f1c624d58ad47e408ffa3ef0 100644
--- a/app/Entities/Episode.php
+++ b/app/Entities/Episode.php
@@ -25,20 +25,10 @@ class Episode extends Entity
     protected $link;
 
     /**
-     * @var \CodeIgniter\Files\File
+     * @var \App\Entities\Image
      */
     protected $image;
 
-    /**
-     * @var string
-     */
-    protected $image_media_path;
-
-    /**
-     * @var string
-     */
-    protected $image_url;
-
     /**
      * @var \CodeIgniter\Files\File
      */
@@ -98,33 +88,30 @@ class Episode extends Entity
             (!($image instanceof \CodeIgniter\HTTP\Files\UploadedFile) ||
                 $image->isValid())
         ) {
+            helper('media');
+
             // check whether the user has inputted an image and store it
             $this->attributes['image_uri'] = save_podcast_media(
                 $image,
                 $this->getPodcast()->name,
                 $this->attributes['slug']
             );
+
+            $this->image = new \App\Entities\Image(
+                $this->attributes['image_uri']
+            );
+            $this->image->saveSizes();
         }
 
         return $this;
     }
 
-    public function getImage(): \CodeIgniter\Files\File
-    {
-        return new \CodeIgniter\Files\File($this->getImageMediaPath());
-    }
-
-    public function getImageMediaPath(): string
-    {
-        return media_path($this->attributes['image_uri']);
-    }
-
-    public function getImageUrl(): string
+    public function getImage(): \App\Entities\Image
     {
         if ($image_uri = $this->attributes['image_uri']) {
-            return media_url($image_uri);
+            return new \App\Entities\Image($image_uri);
         }
-        return $this->getPodcast()->image_url;
+        return $this->getPodcast()->image;
     }
 
     /**
diff --git a/app/Entities/Image.php b/app/Entities/Image.php
new file mode 100644
index 0000000000000000000000000000000000000000..0f64b16cb8c27fa72fb70782aab0de37e5f07545
--- /dev/null
+++ b/app/Entities/Image.php
@@ -0,0 +1,151 @@
+<?php
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace App\Entities;
+
+use CodeIgniter\Entity;
+
+class Image extends Entity
+{
+    /**
+     * @var string
+     */
+    protected $original_path;
+
+    /**
+     * @var string
+     */
+    protected $original_url;
+
+    /**
+     * @var string
+     */
+    protected $thumbnail_path;
+
+    /**
+     * @var string
+     */
+    protected $thumbnail_url;
+
+    /**
+     * @var string
+     */
+    protected $medium_path;
+
+    /**
+     * @var string
+     */
+    protected $medium_url;
+
+    /**
+     * @var string
+     */
+    protected $large_path;
+
+    /**
+     * @var string
+     */
+    protected $large_url;
+
+    /**
+     * @var string
+     */
+    protected $feed_path;
+
+    /**
+     * @var string
+     */
+    protected $feed_url;
+
+    /**
+     * @var string
+     */
+    protected $id3_path;
+
+    public function __construct($originalUri)
+    {
+        helper('media');
+
+        $originalPath = media_path($originalUri);
+
+        [
+            'filename' => $filename,
+            'dirname' => $dirname,
+            'extension' => $extension,
+        ] = pathinfo($originalPath);
+
+        // load images extensions from config
+        $imageConfig = config('Images');
+        $thumbnailExtension = $imageConfig->thumbnailExtension;
+        $mediumExtension = $imageConfig->mediumExtension;
+        $largeExtension = $imageConfig->largeExtension;
+        $feedExtension = $imageConfig->feedExtension;
+        $id3Extension = $imageConfig->id3Extension;
+
+        $thumbnail =
+            $dirname . '/' . $filename . $thumbnailExtension . '.' . $extension;
+        $medium =
+            $dirname . '/' . $filename . $mediumExtension . '.' . $extension;
+        $large =
+            $dirname . '/' . $filename . $largeExtension . '.' . $extension;
+        $feed = $dirname . '/' . $filename . $feedExtension . '.' . $extension;
+        $id3 = $dirname . '/' . $filename . $id3Extension . '.' . $extension;
+
+        parent::__construct([
+            'original_path' => $originalPath,
+            'original_url' => media_url($originalUri),
+            'thumbnail_path' => $thumbnail,
+            'thumbnail_url' => base_url($thumbnail),
+            'medium_path' => $medium,
+            'medium_url' => base_url($medium),
+            'large_path' => $large,
+            'large_url' => base_url($large),
+            'feed_path' => $feed,
+            'feed_url' => base_url($feed),
+            'id3_path' => $id3,
+        ]);
+    }
+
+    public function saveSizes()
+    {
+        // load images sizes from config
+        $imageConfig = config('Images');
+        $thumbnailSize = $imageConfig->thumbnailSize;
+        $mediumSize = $imageConfig->mediumSize;
+        $largeSize = $imageConfig->largeSize;
+        $feedSize = $imageConfig->feedSize;
+        $id3Size = $imageConfig->id3Size;
+
+        $imageService = \Config\Services::image();
+
+        $imageService
+            ->withFile($this->attributes['original_path'])
+            ->resize($thumbnailSize, $thumbnailSize)
+            ->save($this->attributes['thumbnail_path']);
+
+        $imageService
+            ->withFile($this->attributes['original_path'])
+            ->resize($mediumSize, $mediumSize)
+            ->save($this->attributes['medium_path']);
+
+        $imageService
+            ->withFile($this->attributes['original_path'])
+            ->resize($largeSize, $largeSize)
+            ->save($this->attributes['large_path']);
+
+        $imageService
+            ->withFile($this->attributes['original_path'])
+            ->resize($feedSize, $feedSize)
+            ->save($this->attributes['feed_path']);
+
+        $imageService
+            ->withFile($this->attributes['original_path'])
+            ->resize($id3Size, $id3Size)
+            ->save($this->attributes['id3_path']);
+    }
+}
diff --git a/app/Entities/Podcast.php b/app/Entities/Podcast.php
index 2d6ea40d9cff4f43a8c027a9552106c0cb69eb90..0a8a273ba075493ca51b1028ebb1ec5a6c75d6ae 100644
--- a/app/Entities/Podcast.php
+++ b/app/Entities/Podcast.php
@@ -23,20 +23,10 @@ class Podcast extends Entity
     protected $link;
 
     /**
-     * @var \CodeIgniter\Files\File
+     * @var \App\Entities\Image
      */
     protected $image;
 
-    /**
-     * @var string
-     */
-    protected $image_media_path;
-
-    /**
-     * @var string
-     */
-    protected $image_url;
-
     /**
      * @var \App\Entities\Episode[]
      */
@@ -101,24 +91,18 @@ class Podcast extends Entity
                 $this->attributes['name'],
                 'cover'
             );
-
-            return $this;
+            $this->image = new \App\Entities\Image(
+                $this->attributes['image_uri']
+            );
+            $this->image->saveSizes();
         }
-    }
 
-    public function getImage()
-    {
-        return new \CodeIgniter\Files\File($this->getImageMediaPath());
-    }
-
-    public function getImageMediaPath()
-    {
-        return media_path($this->attributes['image_uri']);
+        return $this;
     }
 
-    public function getImageUrl()
+    public function getImage()
     {
-        return media_url($this->attributes['image_uri']);
+        return new \App\Entities\Image($this->attributes['image_uri']);
     }
 
     public function getLink()
diff --git a/app/Helpers/id3_helper.php b/app/Helpers/id3_helper.php
index 15ab043ba360bb31a30677065e00c4d6037f99f7..a7c1685a54236f07bbc0d24520c19e83c2abc596 100644
--- a/app/Helpers/id3_helper.php
+++ b/app/Helpers/id3_helper.php
@@ -47,7 +47,7 @@ function write_enclosure_tags($episode)
     $tagwriter->tagformats = ['id3v2.4'];
     $tagwriter->tag_encoding = $TextEncoding;
 
-    $cover = new \CodeIgniter\Files\File($episode->image_media_path);
+    $cover = new \CodeIgniter\Files\File($episode->image->id3_path);
 
     $APICdata = file_get_contents($cover->getRealPath());
 
diff --git a/app/Helpers/media_helper.php b/app/Helpers/media_helper.php
index 594bb009dfef5e18e6cbb2ce764c05a587a5b61b..a3b28279e285c68abe46ff91745b2200e1be5252 100644
--- a/app/Helpers/media_helper.php
+++ b/app/Helpers/media_helper.php
@@ -19,17 +19,15 @@ function save_podcast_media($file, $podcast_name, $media_name)
 {
     $file_name = $media_name . '.' . $file->getExtension();
 
-    if (!file_exists(config('App')->mediaRoot . '/' . $podcast_name)) {
-        mkdir(config('App')->mediaRoot . '/' . $podcast_name, 0777, true);
-        touch(config('App')->mediaRoot . '/' . $podcast_name . '/index.html');
+    $mediaRoot = config('App')->mediaRoot;
+
+    if (!file_exists($mediaRoot . '/' . $podcast_name)) {
+        mkdir($mediaRoot . '/' . $podcast_name, 0777, true);
+        touch($mediaRoot . '/' . $podcast_name . '/index.html');
     }
 
     // move to media folder and overwrite file if already existing
-    $file->move(
-        config('App')->mediaRoot . '/' . $podcast_name . '/',
-        $file_name,
-        true
-    );
+    $file->move($mediaRoot . '/' . $podcast_name . '/', $file_name, true);
 
     return $podcast_name . '/' . $file_name;
 }
@@ -64,3 +62,15 @@ function media_path($uri = ''): string
 
     return config('App')->mediaRoot . '/' . $uri;
 }
+
+/**
+ * Return the media base URL to use in views
+ *
+ * @param  mixed  $uri      URI string or array of URI segments
+ * @param  string $protocol
+ * @return string
+ */
+function media_url($uri = '', string $protocol = null): string
+{
+    return base_url(config('App')->mediaRoot . '/' . $uri, $protocol);
+}
diff --git a/app/Helpers/rss_helper.php b/app/Helpers/rss_helper.php
index 8ba85770e5165b042d7dc9d093dc13250dcc46d7..68da0f2ae1d68daea201adbd74a46e7158b5defc 100644
--- a/app/Helpers/rss_helper.php
+++ b/app/Helpers/rss_helper.php
@@ -57,7 +57,7 @@ function get_rss_feed($podcast)
     $channel->addChild('title', $podcast->title);
     $channel->addChildWithCDATA('description', $podcast->description_html);
     $itunes_image = $channel->addChild('image', null, $itunes_namespace);
-    $itunes_image->addAttribute('href', $podcast->image_url);
+    $itunes_image->addAttribute('href', $podcast->image->url);
     $channel->addChild('language', $podcast->language);
 
     $itunes_category = $channel->addChild('category', null, $itunes_namespace);
@@ -106,7 +106,7 @@ function get_rss_feed($podcast)
         $channel->addChild('complete', 'Yes', $itunes_namespace);
 
     $image = $channel->addChild('image');
-    $image->addChild('url', $podcast->image_url);
+    $image->addChild('url', $podcast->image->feed_url);
     $image->addChild('title', $podcast->title);
     $image->addChild('link', $podcast->link);
 
@@ -136,7 +136,7 @@ function get_rss_feed($podcast)
             null,
             $itunes_namespace
         );
-        $episode_itunes_image->addAttribute('href', $episode->image_url);
+        $episode_itunes_image->addAttribute('href', $episode->image->feed_url);
         $item->addChild(
             'explicit',
             $episode->explicit ? 'true' : 'false',
diff --git a/app/Helpers/url_helper.php b/app/Helpers/url_helper.php
deleted file mode 100644
index d1cf375827df23b1674faf1040c3691a37c502f3..0000000000000000000000000000000000000000
--- a/app/Helpers/url_helper.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-/**
- * @copyright  2020 Podlibre
- * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
- * @link       https://castopod.org/
- */
-
-/**
- * Return the media base URL to use in views
- *
- * @param  mixed  $uri      URI string or array of URI segments
- * @param  string $protocol
- * @return string
- */
-function media_url($uri = '', string $protocol = null): string
-{
-    return base_url(config('App')->mediaRoot . '/' . $uri, $protocol);
-}
diff --git a/app/Language/en/Common.php b/app/Language/en/Common.php
index 237019ad5d8b620916cb4d0600eacaefcea3f0be..ac242f8f74988b3be13cc12a11e748f78efd60cd 100644
--- a/app/Language/en/Common.php
+++ b/app/Language/en/Common.php
@@ -12,4 +12,8 @@ return [
     'mediumDate' => '{0,date,medium}',
     'duration' => '{0,duration}',
     'powered_by' => 'Powered by {castopod}.',
+    'forms' => [
+        'image_size_hint' =>
+            'Image must be squared with at least 1400px wide and tall.',
+    ],
 ];
diff --git a/app/Language/en/Validation.php b/app/Language/en/Validation.php
index 6672dd852cbbccbbf94437ea9620c16844b7741f..f987763075446595d6043faecf98844a62105a89 100644
--- a/app/Language/en/Validation.php
+++ b/app/Language/en/Validation.php
@@ -9,4 +9,8 @@
 return [
     'not_in_protected_slugs' =>
         'The {field} field conflicts with one of the gateway routes (admin, auth or install).',
+    'min_dims' =>
+        '{field} is either not an image, or it is not wide or tall enough.',
+    'is_image_squared' =>
+        '{field} is either not an image, or it is not squared (width and height differ).',
 ];
diff --git a/app/Validation/FileRules.php b/app/Validation/FileRules.php
new file mode 100644
index 0000000000000000000000000000000000000000..3e8552602e127eb2f7d2f76c939d470200b1301e
--- /dev/null
+++ b/app/Validation/FileRules.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @copyright  2020 Podlibre
+ * @license    https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
+ * @link       https://castopod.org/
+ */
+
+namespace App\Validation;
+
+use CodeIgniter\Validation\FileRules as ValidationFileRules;
+
+class FileRules extends ValidationFileRules
+{
+    /**
+     * Checks an uploaded file to verify that the dimensions are within
+     * a specified allowable dimension.
+     *
+     * @param string|null $blank
+     * @param string      $params
+     *
+     * @return boolean
+     */
+    public function min_dims(string $blank = null, string $params): bool
+    {
+        // Grab the file name off the top of the $params
+        // after we split it.
+        $params = explode(',', $params);
+        $name = array_shift($params);
+
+        if (!($files = $this->request->getFileMultiple($name))) {
+            $files = [$this->request->getFile($name)];
+        }
+
+        foreach ($files as $file) {
+            if (is_null($file)) {
+                return false;
+            }
+
+            if ($file->getError() === UPLOAD_ERR_NO_FILE) {
+                return true;
+            }
+
+            // Get Parameter sizes
+            $minWidth = $params[0] ?? 0;
+            $minHeight = $params[1] ?? 0;
+
+            // Get uploaded image size
+            $info = getimagesize($file->getTempName());
+            $fileWidth = $info[0];
+            $fileHeight = $info[1];
+
+            if ($fileWidth < $minWidth || $fileHeight < $minHeight) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    //--------------------------------------------------------------------
+
+    /**
+     * Checks an uploaded file to verify that the image ratio is of 1:1
+     *
+     * @param string|null $blank
+     * @param string      $params
+     *
+     * @return boolean
+     */
+    public function is_image_squared(string $blank = null, string $params): bool
+    {
+        // Grab the file name off the top of the $params
+        // after we split it.
+        $params = explode(',', $params);
+        $name = array_shift($params);
+
+        if (!($files = $this->request->getFileMultiple($name))) {
+            $files = [$this->request->getFile($name)];
+        }
+
+        foreach ($files as $file) {
+            if (is_null($file)) {
+                return false;
+            }
+
+            if ($file->getError() === UPLOAD_ERR_NO_FILE) {
+                return true;
+            }
+
+            // Get uploaded image size
+            $info = getimagesize($file->getTempName());
+            $fileWidth = $info[0];
+            $fileHeight = $info[1];
+
+            if ($fileWidth != $fileHeight) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    //--------------------------------------------------------------------
+}
diff --git a/app/Validation/Rules.php b/app/Validation/Rules.php
index 6f264caecbaef3a3579604893a0e5ea308097168..4e98e01f5ba085f61f25b97cac13f4b4f0c19c9a 100644
--- a/app/Validation/Rules.php
+++ b/app/Validation/Rules.php
@@ -27,4 +27,6 @@ class Rules
         ];
         return !in_array($value, $protectedSlugs, true);
     }
+
+    //--------------------------------------------------------------------
 }
diff --git a/app/Views/admin/_partials/_episode-card.php b/app/Views/admin/_partials/_episode-card.php
index 353674de7323ffc978eec74c35287bee2dcfa4d0..4ff75d35ce94b6439bc99644c0713b4c1fce548f 100644
--- a/app/Views/admin/_partials/_episode-card.php
+++ b/app/Views/admin/_partials/_episode-card.php
@@ -1,5 +1,8 @@
 <article class="flex w-full max-w-lg mb-4 bg-white border rounded shadow">
-    <img src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-32 h-32 rounded-l" />
+    <img
+    loading="lazy"
+    src="<?= $episode->image->thumbnail_url ?>"
+    alt="<?= $episode->title ?>" class="object-cover w-32 h-32 rounded-l" />
     <div class="flex flex-col flex-1 px-4 py-2">
         <a href="<?= route_to(
             'episode-view',
diff --git a/app/Views/admin/_partials/_podcast-card.php b/app/Views/admin/_partials/_podcast-card.php
index 0db3051be5cf64aa4297425a1cba65643fca38fa..00d7f441166acabb091b2bcd3daea66e00869d4c 100644
--- a/app/Views/admin/_partials/_podcast-card.php
+++ b/app/Views/admin/_partials/_podcast-card.php
@@ -1,5 +1,8 @@
 <article class="w-48 h-full mb-4 mr-4 overflow-hidden bg-white border rounded shadow">
-    <img alt="<?= $podcast->title ?>" src="<?= $podcast->image_url ?>" class="object-cover w-full h-40" />
+    <img
+    alt="<?= $podcast->title ?>"
+    src="<?= $podcast->image
+        ->thumbnail_url ?>" class="object-cover w-full h-40" />
     <div class="p-2">
         <a href="<?= route_to(
             'podcast-view',
diff --git a/app/Views/admin/episode/create.php b/app/Views/admin/episode/create.php
index c19a0973496765819a81e1f7cc6143acd2339518..54e9832a2d6399c1efc86ef91759c49da92f3640 100644
--- a/app/Views/admin/episode/create.php
+++ b/app/Views/admin/episode/create.php
@@ -23,6 +23,18 @@
     'accept' => '.mp3,.m4a',
 ]) ?>
 
+<?= form_label(lang('Episode.form.image'), 'image') ?>
+<?= form_input([
+    'id' => 'image',
+    'name' => 'image',
+    'class' => 'form-input',
+    'type' => 'file',
+    'accept' => '.jpg,.jpeg,.png',
+]) ?>
+<small class="mb-4 text-gray-600"><?= lang(
+    'Common.forms.image_size_hint'
+) ?></small>
+
 <?= form_label(lang('Episode.form.title'), 'title') ?>
 <?= form_input([
     'id' => 'title',
@@ -87,16 +99,6 @@
 </div>
 <?= form_fieldset_close() ?>
 
-
-<?= form_label(lang('Episode.form.image'), 'image') ?>
-<?= form_input([
-    'id' => 'image',
-    'name' => 'image',
-    'class' => 'form-input mb-4',
-    'type' => 'file',
-    'accept' => '.jpg,.jpeg,.png',
-]) ?>
-
 <?= form_label(lang('Episode.form.season_number'), 'season_number') ?>
 <?= form_input([
     'id' => 'season_number',
diff --git a/app/Views/admin/episode/edit.php b/app/Views/admin/episode/edit.php
index 7076114fe32c5534fa6c77d78a4a9633ee961344..9d0ad5211d9fc8508757e49db45453394e38559b 100644
--- a/app/Views/admin/episode/edit.php
+++ b/app/Views/admin/episode/edit.php
@@ -22,6 +22,23 @@
     'accept' => '.mp3,.m4a',
 ]) ?>
 
+<?= form_label(lang('Episode.form.image'), 'image') ?>
+<img
+    src="<?= $episode->image->thumbnail_url ?>"
+    alt="<?= $episode->title ?>"
+    class="object-cover w-32 h-32"
+/>
+<?= form_input([
+    'id' => 'image',
+    'name' => 'image',
+    'class' => 'form-input',
+    'type' => 'file',
+    'accept' => '.jpg,.jpeg,.png',
+]) ?>
+<small class="mb-4 text-gray-600"><?= lang(
+    'Common.forms.image_size_hint'
+) ?></small>
+
 <?= form_label(lang('Episode.form.title'), 'title') ?>
 <?= form_input([
     'id' => 'title',
@@ -94,16 +111,6 @@
 </div>
 <?= form_fieldset_close() ?>
 
-<?= form_label(lang('Episode.form.image'), 'image') ?>
-<img src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-32 h-32" />
-<?= form_input([
-    'id' => 'image',
-    'name' => 'image',
-    'class' => 'form-input mb-4',
-    'type' => 'file',
-    'accept' => '.jpg,.jpeg,.png',
-]) ?>
-
 <?= form_label(lang('Episode.form.season_number'), 'season_number') ?>
 <?= form_input([
     'id' => 'season_number',
diff --git a/app/Views/admin/episode/view.php b/app/Views/admin/episode/view.php
index 2b154a6dd5231416ec7811c8e52302a756ca265c..d3ccaa1e31759e6b33b0823946fda17d2222a385 100644
--- a/app/Views/admin/episode/view.php
+++ b/app/Views/admin/episode/view.php
@@ -6,7 +6,11 @@
 
 <?= $this->section('content') ?>
 
-<img src="<?= $episode->image_url ?>" alt="Episode cover"  class="object-cover w-40 h-40 mb-6" />
+<img
+    src="<?= $episode->image->medium_url ?>"
+    alt="Episode cover"
+    class="object-cover w-40 h-40 mb-6"
+/>
 <audio controls preload="none" class="mb-12">
   <source src="<?= $episode->enclosure_url ?>" type="<?= $episode->enclosure_type ?>">
   Your browser does not support the audio tag.
diff --git a/app/Views/admin/podcast/create.php b/app/Views/admin/podcast/create.php
index e27277c9a2507d25476f60b7ad438a993a2bbe79..4832413d06d8a196c47963dd2cf141a18d24bca5 100644
--- a/app/Views/admin/podcast/create.php
+++ b/app/Views/admin/podcast/create.php
@@ -13,6 +13,19 @@
 ]) ?>
 <?= csrf_field() ?>
 
+<?= form_label(lang('Podcast.form.image'), 'image') ?>
+<?= form_input([
+    'id' => 'image',
+    'name' => 'image',
+    'class' => 'form-input',
+    'required' => 'required',
+    'type' => 'file',
+    'accept' => '.jpg,.jpeg,.png',
+]) ?>
+<small class="mb-4 text-gray-600"><?= lang(
+    'Common.forms.image_size_hint'
+) ?></small>
+
 <?= form_label(lang('Podcast.form.title'), 'title') ?>
 <?= form_input([
     'id' => 'title',
@@ -54,7 +67,6 @@
         [
             'id' => 'episode_description_footer',
             'name' => 'episode_description_footer',
-
             'class' => 'form-textarea',
         ],
         old('episode_description_footer', '', false),
@@ -62,16 +74,6 @@
     ) ?>
 </div>
 
-<?= form_label(lang('Podcast.form.image'), 'image') ?>
-<?= form_input([
-    'id' => 'image',
-    'name' => 'image',
-    'class' => 'form-input mb-4',
-    'required' => 'required',
-    'type' => 'file',
-    'accept' => '.jpg,.jpeg,.png',
-]) ?>
-
 <?= form_label(lang('Podcast.form.language'), 'language') ?>
 <?= form_dropdown('language', $languageOptions, old('language', $browserLang), [
     'id' => 'language',
@@ -122,7 +124,9 @@
     'value' => old('author'),
 ]) ?>
 
-<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
+<?= form_fieldset('', [
+    'class' => 'flex flex-col mb-4',
+]) ?>
     <legend><?= lang('Podcast.form.type.label') ?></legend>
     <label for="episodic" class="inline-flex items-center">
         <?= form_radio(
diff --git a/app/Views/admin/podcast/edit.php b/app/Views/admin/podcast/edit.php
index 99c597e80fc86557d65663c1aad4c9eaf460fedf..73271a3f28522b24823bda354255445c3e9e30f8 100644
--- a/app/Views/admin/podcast/edit.php
+++ b/app/Views/admin/podcast/edit.php
@@ -13,6 +13,22 @@
 ]) ?>
 <?= csrf_field() ?>
 
+<?= form_label(lang('Podcast.form.image'), 'image') ?>
+<img
+    src="<?= $podcast->image->thumbnail_url ?>"
+    alt="<?= $podcast->title ?>"
+    class="object-cover w-32 h-32"
+/>
+<?= form_input([
+    'id' => 'image',
+    'name' => 'image',
+    'class' => 'form-input',
+    'type' => 'file',
+    'accept' => '.jpg,.jpeg,.png',
+]) ?>
+<small class="mb-4 text-gray-600"><?= lang(
+    'Common.forms.image_size_hint'
+) ?></small>
 
 <?= form_label(lang('Podcast.form.title'), 'title') ?>
 <?= form_input([
@@ -66,16 +82,6 @@
     ) ?>
 </div>
 
-<?= form_label(lang('Podcast.form.image'), 'image') ?>
-<img src="<?= $podcast->image_url ?>" alt="<?= $podcast->title ?>" class="object-cover w-32 h-32" />
-<?= form_input([
-    'id' => 'image',
-    'name' => 'image',
-    'class' => 'form-input mb-4',
-    'type' => 'file',
-    'accept' => '.jpg,.jpeg,.png',
-]) ?>
-
 <?= form_label(lang('Podcast.form.language'), 'language') ?>
 <?= form_dropdown(
     'language',
diff --git a/app/Views/admin/podcast/import.php b/app/Views/admin/podcast/import.php
index 5bbaf110bd25bb30993034a95c10da4f01a7f584..853de8991be5e534a33b25ec554aaa75a70d0ede 100644
--- a/app/Views/admin/podcast/import.php
+++ b/app/Views/admin/podcast/import.php
@@ -7,28 +7,33 @@
 
 <?= $this->section('content') ?>
 
-<?= form_open_multipart(route_to('podcast_import'), [
+<?= form_open_multipart(route_to('rzqr'), [
     'method' => 'post',
     'class' => 'flex flex-col max-w-md',
 ]) ?>
 <?= csrf_field() ?>
 
+<?= form_label(lang('Podcast.form_import.name'), 'name') ?>
+<?= form_input([
+    'id' => 'name',
+    'name' => 'name',
+    'class' => 'form-input mb-4',
+    'value' => old('name'),
+    'required' => 'required',
+]) ?>
 
-<div class="flex flex-col mb-4">
-    <label for="name"><?= lang('Podcast.form_import.name') ?></label>
-    <input type="text" class="form-input" id="name" name="name" value="<?= old(
-        'name'
-    ) ?>" required />
-</div>
-
-<div class="flex flex-col mb-4">
-    <label for="name"><?= lang(
-        'Podcast.form_import.imported_feed_url'
-    ) ?></label>
-    <input type="text" class="form-input" id="imported_feed_url" name="imported_feed_url" value="<?= old(
-        'imported_feed_url'
-    ) ?>" required />
-</div>
+<?= form_label(
+    lang('Podcast.form_import.imported_feed_url'),
+    'imported_feed_url'
+) ?>
+<?= form_input([
+    'id' => 'imported_feed_url',
+    'name' => 'imported_feed_url',
+    'class' => 'form-input mb-4',
+    'value' => old('imported_feed_url'),
+    'type' => 'url',
+    'required' => 'required',
+]) ?>
 
 <?= form_label(lang('Podcast.form.language'), 'language') ?>
 <?= form_dropdown('language', $languageOptions, old('language', $browserLang), [
@@ -44,9 +49,8 @@
     'required' => 'required',
 ]) ?>
 
-<?= form_fieldset(lang('Podcast.form_import.slug_field.label'), [
-    'class' => 'flex flex-col mb-4',
-]) ?>
+<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
+    <legend><?= lang('Podcast.form_import.slug_field.label') ?></legend>
     <label for="link" class="inline-flex items-center">
         <?= form_radio(
             ['id' => 'link', 'name' => 'slug_field', 'class' => 'form-radio'],
@@ -69,9 +73,8 @@
     </label>
 <?= form_fieldset_close() ?>
 
-<?= form_fieldset(lang('Podcast.form_import.description_field.label'), [
-    'class' => 'flex flex-col mb-4',
-]) ?>
+<?= form_fieldset('', ['class' => 'flex flex-col mb-4']) ?>
+    <legend><?= lang('Podcast.form_import.description_field.label') ?></legend>
     <label for="description" class="inline-flex items-center">
         <?= form_radio(
             [
@@ -88,7 +91,7 @@
             'Podcast.form_import.description_field.description'
         ) ?></span>
     </label>
-    <label for="subtitle_summary" class="inline-flex items-center">
+    <label for="summary" class="inline-flex items-center">
         <?= form_radio(
             [
                 'id' => 'summary',
@@ -136,27 +139,30 @@
     <span class="ml-2"><?= lang('Podcast.form_import.force_renumber') ?></span>
 </label>
 
-<div class="flex flex-col mb-4">
-    <label for="name"><?= lang('Podcast.form_import.season_number') ?></label>
-    <input type="text" class="form-input" id="season_number" name="season_number" value="<?= old(
-        'season_number'
-    ) ?>" />
-</div>
-
-<div class="flex flex-col mb-4">
-    <label for="max_episodes"><?= lang(
-        'Podcast.form_import.max_episodes'
-    ) ?></label>
-    <input type="text" class="form-input" id="max_episodes" name="max_episodes" value="<?= old(
-        'max_episodes'
-    ) ?>" />
-</div>
-
-<button type="submit" name="submit"  onsubmit="this.disabled=true; this.value='<?= lang(
-    'Podcast.form_import.submit_importing'
-) ?>';" class="self-end px-4 py-2 bg-gray-200"><?= lang(
-    'Podcast.form_import.submit_import'
-) ?></button>
+<?= form_label(lang('Podcast.form_import.season_number'), 'season_number') ?>
+<?= form_input([
+    'id' => 'season_number',
+    'name' => 'season_number',
+    'class' => 'form-input mb-4',
+    'value' => old('season_number'),
+    'type' => 'number',
+]) ?>
+
+<?= form_label(lang('Podcast.form_import.max_episodes'), 'max_episodes') ?>
+<?= form_input([
+    'id' => 'max_episodes',
+    'name' => 'max_episodes',
+    'class' => 'form-input mb-4',
+    'value' => old('max_episodes'),
+    'type' => 'number',
+]) ?>
+
+<?= form_button([
+    'content' => lang('Podcast.form_import.submit_import'),
+    'type' => 'submit',
+    'class' => 'self-end px-4 py-2 bg-gray-200',
+]) ?>
+
 <?= form_close() ?>
 
 
diff --git a/app/Views/admin/podcast/view.php b/app/Views/admin/podcast/view.php
index 52eea1a532078ce82f475253a6cf3fb304eedd14..e1fdba10c0f304fdd2ed90408a51b42672e9202d 100644
--- a/app/Views/admin/podcast/view.php
+++ b/app/Views/admin/podcast/view.php
@@ -18,7 +18,11 @@
 <?= $this->endSection() ?>
 
 <?= $this->section('content') ?>
-    <img class="w-64 mb-4" src="<?= $podcast->image_url ?>" alt="<?= $podcast->title ?>" />
+    <img
+        class="w-64 mb-4"
+        src="<?= $podcast->image->medium_url ?>"
+        alt="<?= $podcast->title ?>"
+    />
     <a class="inline-flex px-2 py-1 mb-2 text-white bg-yellow-700 hover:bg-yellow-800" href="<?= route_to(
         'contributor-list',
         $podcast->id
diff --git a/app/Views/episode.php b/app/Views/episode.php
index 1fabf4fb71568e71dcd2ba78b0e8b0665ea76b21..dbdd6a2ea31d830a84bd2a4a8e9d4fbb2fb298e3 100644
--- a/app/Views/episode.php
+++ b/app/Views/episode.php
@@ -1,6 +1,6 @@
 <?= helper('page') ?>
 <!DOCTYPE html>
-<html lang="en">
+<html lang="<?= $episode->podcast->language ?>">
 
 <head>
     <meta charset="UTF-8"/>
@@ -14,14 +14,15 @@
 <body class="flex flex-col min-h-screen mx-auto">
     <header class="border-b bg-gradient-to-tr from-gray-900 to-gray-800">
         <div class="container flex items-start px-2 py-2 mx-auto">
-          <img class="w-12 h-12 mr-2 rounded cover" src="<?= $episode->podcast
-              ->image_url ?>" alt="<?= $episode->podcast->title ?>" />
-          <a href="<?= route_to(
-              'podcast',
-              $episode->podcast->name
-          ) ?>" class="flex flex-col text-lg leading-tight text-white" title="<?= lang(
-    'Episode.back_to_podcast'
-) ?>">
+          <img
+            class="w-12 h-12 mr-2 rounded cover"
+            src="<?= $episode->podcast->image->thumbnail_url ?>"
+            alt="<?= $episode->podcast->title ?>"
+          />
+          <a
+            href="<?= route_to('podcast', $episode->podcast->name) ?>"
+            class="flex flex-col text-lg leading-tight text-white"
+            title="<?= lang('Episode.back_to_podcast') ?>">
             <?= $episode->podcast->title ?>
             <span class="text-sm text-gray-300">
                 @<?= $episode->podcast->name ?>
@@ -57,7 +58,8 @@
             <?php endif; ?>
       </nav>
       <header class="flex flex-col items-center px-4 md:items-stretch md:justify-center md:flex-row">
-        <img src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-full max-w-xs mb-2 rounded-lg md:mb-0 md:mr-4" />
+        <img src="<?= $episode->image->medium_url ?>"
+        alt="<?= $episode->title ?>" class="object-cover w-full max-w-xs mb-2 rounded-lg md:mb-0 md:mr-4" />
         <div class="flex flex-col w-full max-w-sm">
           <h1 class="text-lg font-semibold md:text-2xl"><?= $episode->title ?></h1>
           <?php if ($episode->number): ?>
diff --git a/app/Views/home.php b/app/Views/home.php
index 8a7e7f962b913c4e8c1adabf36fbf55e7906f7a4..4a8fe348691d8f2693bac808a928dc7e7d85f26a 100644
--- a/app/Views/home.php
+++ b/app/Views/home.php
@@ -12,7 +12,9 @@
         <?php foreach ($podcasts as $podcast): ?>
             <a href="<?= route_to('podcast', $podcast->name) ?>">
                 <article class="w-48 h-full p-2 mb-4 mr-4 border shadow-sm hover:bg-gray-100 hover:shadow">
-                    <img alt="<?= $podcast->title ?>" src="<?= $podcast->image_url ?>" class="object-cover w-full h-40 mb-2" />
+                    <img alt="<?= $podcast->title ?>"
+                    src="<?= $podcast->image->thumbnail_url ?>"
+                    class="object-cover w-full h-40 mb-2" />
                     <h2 class="font-semibold leading-tight"><?= $podcast->title ?></h2>
                     <p class="text-gray-600">@<?= $podcast->name ?></p>
                 </article>
diff --git a/app/Views/podcast.php b/app/Views/podcast.php
index 2dcb69a8f92be3238e55c3bf41c63b90906a3573..212be0da39b02a7f1ac09058452fa07cc0a515a1 100644
--- a/app/Views/podcast.php
+++ b/app/Views/podcast.php
@@ -17,7 +17,8 @@
     <main class="flex-1 bg-gray-200">
         <header class="border-b bg-gradient-to-tr from-gray-900 to-gray-800">
             <div class="flex flex-col items-center justify-center md:items-stretch md:mx-auto md:container md:py-12 md:flex-row ">
-                <img src="<?= $podcast->image_url ?>" alt="Podcast cover" class="object-cover w-full max-w-xs m-4 rounded-lg shadow-xl" />
+                <img src="<?= $podcast->image->medium_url ?>"
+                alt="<?= $podcast->title ?>" class="object-cover w-full max-w-xs m-4 rounded-lg shadow-xl" />
                 <div class="w-full p-4 bg-white md:w-auto md:text-white md:bg-transparent">
                     <h1 class="text-2xl font-semibold leading-tight"><?= $podcast->title ?> <span class="text-lg font-normal opacity-75">@<?= $podcast->name ?></span></h1>
                     <div class="flex items-center mb-4">
@@ -99,7 +100,10 @@
                     </h1>
                     <?php foreach ($episodes as $episode): ?>
                         <article class="flex w-full max-w-lg p-4 mx-auto">
-                            <img loading="lazy" src="<?= $episode->image_url ?>" alt="<?= $episode->title ?>" class="object-cover w-20 h-20 mr-2 rounded-lg" />
+                            <img
+                            loading="lazy"
+                            src="<?= $episode->image->thumbnail_url ?>"
+                            alt="<?= $episode->title ?>" class="object-cover w-20 h-20 mr-2 rounded-lg" />
                             <div class="flex flex-col flex-1">
                                 <a class="text-sm hover:underline" href="<?= $episode->link ?>">
                                     <h2 class="inline-flex justify-between w-full font-bold leading-none group">
diff --git a/composer.lock b/composer.lock
index e487409e94204a4dbbc1f806c0cdf523eb828d49..d3126548ad7da734a97091f1f41a16d15dbe32fe 100644
--- a/composer.lock
+++ b/composer.lock
@@ -12,12 +12,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/codeigniter4/CodeIgniter4.git",
-                "reference": "9a7e826138bf8940ef8c7a25d59d67b1aebfe0ee"
+                "reference": "9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/9a7e826138bf8940ef8c7a25d59d67b1aebfe0ee",
-                "reference": "9a7e826138bf8940ef8c7a25d59d67b1aebfe0ee",
+                "url": "https://api.github.com/repos/codeigniter4/CodeIgniter4/zipball/9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4",
+                "reference": "9b6eda2729d4a8912ccfe8f8c20587b21ff92ac4",
                 "shasum": ""
             },
             "require": {
@@ -34,7 +34,7 @@
                 "codeigniter4/codeigniter4-standard": "^1.0",
                 "fzaninotto/faker": "^1.9@dev",
                 "mikey179/vfsstream": "1.6.*",
-                "phpstan/phpstan": "^0.12.37",
+                "phpstan/phpstan": "^0.12",
                 "phpunit/phpunit": "^8.5",
                 "predis/predis": "^1.1",
                 "squizlabs/php_codesniffer": "^3.3"
@@ -66,20 +66,20 @@
                 "slack": "https://codeigniterchat.slack.com",
                 "issues": "https://github.com/codeigniter4/CodeIgniter4/issues"
             },
-            "time": "2020-08-17T14:11:23+00:00"
+            "time": "2020-09-07T16:29:38+00:00"
         },
         {
             "name": "composer/ca-bundle",
-            "version": "1.2.7",
+            "version": "1.2.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/composer/ca-bundle.git",
-                "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd"
+                "reference": "8a7ecad675253e4654ea05505233285377405215"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/composer/ca-bundle/zipball/95c63ab2117a72f48f5a55da9740a3273d45b7fd",
-                "reference": "95c63ab2117a72f48f5a55da9740a3273d45b7fd",
+                "url": "https://api.github.com/repos/composer/ca-bundle/zipball/8a7ecad675253e4654ea05505233285377405215",
+                "reference": "8a7ecad675253e4654ea05505233285377405215",
                 "shasum": ""
             },
             "require": {
@@ -127,12 +127,16 @@
                     "url": "https://packagist.com",
                     "type": "custom"
                 },
+                {
+                    "url": "https://github.com/composer",
+                    "type": "github"
+                },
                 {
                     "url": "https://tidelift.com/funding/github/packagist/composer/composer",
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-04-08T08:27:21+00:00"
+            "time": "2020-08-23T12:54:47+00:00"
         },
         {
             "name": "geoip2/geoip2",
@@ -451,23 +455,23 @@
         },
         {
             "name": "laminas/laminas-zendframework-bridge",
-            "version": "1.0.4",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laminas/laminas-zendframework-bridge.git",
-                "reference": "fcd87520e4943d968557803919523772475e8ea3"
+                "reference": "4939c81f63a8a4968c108c440275c94955753b19"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/fcd87520e4943d968557803919523772475e8ea3",
-                "reference": "fcd87520e4943d968557803919523772475e8ea3",
+                "url": "https://api.github.com/repos/laminas/laminas-zendframework-bridge/zipball/4939c81f63a8a4968c108c440275c94955753b19",
+                "reference": "4939c81f63a8a4968c108c440275c94955753b19",
                 "shasum": ""
             },
             "require": {
-                "php": "^5.6 || ^7.0"
+                "php": "^5.6 || ^7.0 || ^8.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1",
+                "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.1 || ^9.3",
                 "squizlabs/php_codesniffer": "^3.5"
             },
             "type": "library",
@@ -505,20 +509,20 @@
                     "type": "community_bridge"
                 }
             ],
-            "time": "2020-05-20T16:45:56+00:00"
+            "time": "2020-08-18T16:34:51+00:00"
         },
         {
             "name": "league/commonmark",
-            "version": "1.5.3",
+            "version": "1.5.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/thephpleague/commonmark.git",
-                "reference": "2574454b97e4103dc4e36917bd783b25624aefcd"
+                "reference": "21819c989e69bab07e933866ad30c7e3f32984ba"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/2574454b97e4103dc4e36917bd783b25624aefcd",
-                "reference": "2574454b97e4103dc4e36917bd783b25624aefcd",
+                "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/21819c989e69bab07e933866ad30c7e3f32984ba",
+                "reference": "21819c989e69bab07e933866ad30c7e3f32984ba",
                 "shasum": ""
             },
             "require": {
@@ -600,7 +604,7 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2020-07-19T22:47:30+00:00"
+            "time": "2020-08-18T01:19:12+00:00"
         },
         {
             "name": "league/html-to-markdown",
@@ -796,12 +800,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/lonnieezell/myth-auth.git",
-                "reference": "d9c9b0e4a8bea9ba6c847dcfefc6645bf1e1d694"
+                "reference": "e838cb8de6ffa118caf2b9909e71776a866c8973"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/d9c9b0e4a8bea9ba6c847dcfefc6645bf1e1d694",
-                "reference": "d9c9b0e4a8bea9ba6c847dcfefc6645bf1e1d694",
+                "url": "https://api.github.com/repos/lonnieezell/myth-auth/zipball/e838cb8de6ffa118caf2b9909e71776a866c8973",
+                "reference": "e838cb8de6ffa118caf2b9909e71776a866c8973",
                 "shasum": ""
             },
             "require": {
@@ -848,7 +852,7 @@
                     "type": "patreon"
                 }
             ],
-            "time": "2020-07-16T14:00:14+00:00"
+            "time": "2020-09-07T03:37:26+00:00"
         },
         {
             "name": "phpoption/phpoption",
diff --git a/package-lock.json b/package-lock.json
index ade2bd829ea4224481e1c3edb2f261b039268bed..bc926e37449949c85555a03579fc22c40b364d72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -25,19 +25,19 @@
       }
     },
     "@babel/core": {
-      "version": "7.11.4",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz",
-      "integrity": "sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg==",
+      "version": "7.11.6",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz",
+      "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.10.4",
-        "@babel/generator": "^7.11.4",
+        "@babel/generator": "^7.11.6",
         "@babel/helper-module-transforms": "^7.11.0",
         "@babel/helpers": "^7.10.4",
-        "@babel/parser": "^7.11.4",
+        "@babel/parser": "^7.11.5",
         "@babel/template": "^7.10.4",
-        "@babel/traverse": "^7.11.0",
-        "@babel/types": "^7.11.0",
+        "@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",
@@ -58,12 +58,12 @@
           }
         },
         "@babel/generator": {
-          "version": "7.11.4",
-          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz",
-          "integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==",
+          "version": "7.11.6",
+          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz",
+          "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==",
           "dev": true,
           "requires": {
-            "@babel/types": "^7.11.0",
+            "@babel/types": "^7.11.5",
             "jsesc": "^2.5.1",
             "source-map": "^0.5.0"
           }
@@ -95,32 +95,32 @@
           }
         },
         "@babel/parser": {
-          "version": "7.11.4",
-          "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz",
-          "integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==",
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz",
+          "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==",
           "dev": true
         },
         "@babel/traverse": {
-          "version": "7.11.0",
-          "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz",
-          "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==",
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz",
+          "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==",
           "dev": true,
           "requires": {
             "@babel/code-frame": "^7.10.4",
-            "@babel/generator": "^7.11.0",
+            "@babel/generator": "^7.11.5",
             "@babel/helper-function-name": "^7.10.4",
             "@babel/helper-split-export-declaration": "^7.11.0",
-            "@babel/parser": "^7.11.0",
-            "@babel/types": "^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": {
-          "version": "7.11.0",
-          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
-          "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
+          "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
           "dev": true,
           "requires": {
             "@babel/helper-validator-identifier": "^7.10.4",
@@ -321,9 +321,9 @@
           "dev": true
         },
         "@babel/types": {
-          "version": "7.11.0",
-          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
-          "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
+          "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
           "dev": true,
           "requires": {
             "@babel/helper-validator-identifier": "^7.10.4",
@@ -421,9 +421,9 @@
           "dev": true
         },
         "@babel/types": {
-          "version": "7.11.0",
-          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
-          "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
+          "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
           "dev": true,
           "requires": {
             "@babel/helper-validator-identifier": "^7.10.4",
@@ -1093,9 +1093,9 @@
       }
     },
     "@babel/preset-env": {
-      "version": "7.11.0",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz",
-      "integrity": "sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg==",
+      "version": "7.11.5",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz",
+      "integrity": "sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA==",
       "dev": true,
       "requires": {
         "@babel/compat-data": "^7.11.0",
@@ -1160,7 +1160,7 @@
         "@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.0",
+        "@babel/types": "^7.11.5",
         "browserslist": "^4.12.0",
         "core-js-compat": "^3.6.2",
         "invariant": "^2.2.2",
@@ -1175,9 +1175,9 @@
           "dev": true
         },
         "@babel/types": {
-          "version": "7.11.0",
-          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
-          "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
+          "version": "7.11.5",
+          "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz",
+          "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==",
           "dev": true,
           "requires": {
             "@babel/helper-validator-identifier": "^7.10.4",
@@ -1774,6 +1774,75 @@
       "integrity": "sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==",
       "dev": true
     },
+    "@eslint/eslintrc": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
+      "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
+      "dev": true,
+      "requires": {
+        "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",
+        "strip-json-comments": "^3.1.1"
+      },
+      "dependencies": {
+        "globals": {
+          "version": "12.4.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+          "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+          "dev": true,
+          "requires": {
+            "type-fest": "^0.8.1"
+          }
+        },
+        "ignore": {
+          "version": "4.0.6",
+          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+          "dev": true
+        },
+        "import-fresh": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+          "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+          "dev": true,
+          "requires": {
+            "parent-module": "^1.0.0",
+            "resolve-from": "^4.0.0"
+          }
+        },
+        "lodash": {
+          "version": "4.17.20",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+          "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+          "dev": true
+        },
+        "resolve-from": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+          "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+          "dev": true
+        },
+        "strip-json-comments": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+          "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+          "dev": true
+        },
+        "type-fest": {
+          "version": "0.8.1",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+          "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+          "dev": true
+        }
+      }
+    },
     "@fullhuman/postcss-purgecss": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz",
@@ -1960,12 +2029,6 @@
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
       "dev": true
     },
-    "@types/eslint-visitor-keys": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
-      "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==",
-      "dev": true
-    },
     "@types/estree": {
       "version": "0.0.39",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
@@ -1973,9 +2036,9 @@
       "dev": true
     },
     "@types/json-schema": {
-      "version": "7.0.5",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
-      "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
+      "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
       "dev": true
     },
     "@types/linkify-it": {
@@ -2111,12 +2174,13 @@
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz",
-      "integrity": "sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz",
+      "integrity": "sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "3.10.1",
+        "@typescript-eslint/experimental-utils": "4.0.1",
+        "@typescript-eslint/scope-manager": "4.0.1",
         "debug": "^4.1.1",
         "functional-red-black-tree": "^1.0.1",
         "regexpp": "^3.0.0",
@@ -2133,47 +2197,57 @@
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz",
-      "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz",
+      "integrity": "sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.3",
-        "@typescript-eslint/types": "3.10.1",
-        "@typescript-eslint/typescript-estree": "3.10.1",
+        "@typescript-eslint/scope-manager": "4.0.1",
+        "@typescript-eslint/types": "4.0.1",
+        "@typescript-eslint/typescript-estree": "4.0.1",
         "eslint-scope": "^5.0.0",
         "eslint-utils": "^2.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz",
-      "integrity": "sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.0.1.tgz",
+      "integrity": "sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==",
       "dev": true,
       "requires": {
-        "@types/eslint-visitor-keys": "^1.0.0",
-        "@typescript-eslint/experimental-utils": "3.10.1",
-        "@typescript-eslint/types": "3.10.1",
-        "@typescript-eslint/typescript-estree": "3.10.1",
-        "eslint-visitor-keys": "^1.1.0"
+        "@typescript-eslint/scope-manager": "4.0.1",
+        "@typescript-eslint/types": "4.0.1",
+        "@typescript-eslint/typescript-estree": "4.0.1",
+        "debug": "^4.1.1"
+      }
+    },
+    "@typescript-eslint/scope-manager": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz",
+      "integrity": "sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "4.0.1",
+        "@typescript-eslint/visitor-keys": "4.0.1"
       }
     },
     "@typescript-eslint/types": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz",
-      "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.0.1.tgz",
+      "integrity": "sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==",
       "dev": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz",
-      "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz",
+      "integrity": "sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/types": "3.10.1",
-        "@typescript-eslint/visitor-keys": "3.10.1",
+        "@typescript-eslint/types": "4.0.1",
+        "@typescript-eslint/visitor-keys": "4.0.1",
         "debug": "^4.1.1",
-        "glob": "^7.1.6",
+        "globby": "^11.0.1",
         "is-glob": "^4.0.1",
         "lodash": "^4.17.15",
         "semver": "^7.3.2",
@@ -2189,12 +2263,13 @@
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz",
-      "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz",
+      "integrity": "sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==",
       "dev": true,
       "requires": {
-        "eslint-visitor-keys": "^1.1.0"
+        "@typescript-eslint/types": "4.0.1",
+        "eslint-visitor-keys": "^2.0.0"
       }
     },
     "JSONStream": {
@@ -2247,9 +2322,9 @@
       }
     },
     "ajv": {
-      "version": "6.12.3",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
-      "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
+      "version": "6.12.4",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
+      "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
       "dev": true,
       "requires": {
         "fast-deep-equal": "^3.1.1",
@@ -2345,12 +2420,6 @@
       "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
       "dev": true
     },
-    "arrify": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
-      "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
-      "dev": true
-    },
     "assign-symbols": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
@@ -2358,9 +2427,9 @@
       "dev": true
     },
     "astral-regex": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
-      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+      "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
       "dev": true
     },
     "at-least-node": {
@@ -2486,9 +2555,9 @@
       "dev": true
     },
     "binary-extensions": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
-      "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+      "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
       "dev": true
     },
     "boolbase": {
@@ -2613,12 +2682,6 @@
       "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
       "dev": true
     },
-    "camelcase": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz",
-      "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==",
-      "dev": true
-    },
     "camelcase-css": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
@@ -2751,9 +2814,9 @@
       "dev": true
     },
     "chokidar": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz",
-      "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==",
+      "version": "3.4.2",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
+      "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
       "dev": true,
       "requires": {
         "anymatch": "~3.1.1",
@@ -2861,12 +2924,54 @@
           "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
           "dev": true
         },
+        "ansi-styles": {
+          "version": "4.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "dev": true,
+          "requires": {
+            "@types/color-name": "^1.1.1",
+            "color-convert": "^2.0.1"
+          }
+        },
+        "astral-regex": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+          "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+          "dev": true
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
         "is-fullwidth-code-point": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
           "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
           "dev": true
         },
+        "slice-ansi": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+          "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "astral-regex": "^2.0.0",
+            "is-fullwidth-code-point": "^3.0.0"
+          }
+        },
         "string-width": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@@ -3037,6 +3142,12 @@
         "simple-swizzle": "^0.2.2"
       }
     },
+    "colorette": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
+      "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+      "dev": true
+    },
     "commander": {
       "version": "6.1.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz",
@@ -4009,12 +4120,13 @@
       "dev": true
     },
     "eslint": {
-      "version": "7.7.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.7.0.tgz",
-      "integrity": "sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==",
+      "version": "7.8.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz",
+      "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
+        "@eslint/eslintrc": "^0.1.3",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
         "cross-spawn": "^7.0.2",
@@ -4024,7 +4136,7 @@
         "eslint-scope": "^5.1.0",
         "eslint-utils": "^2.1.0",
         "eslint-visitor-keys": "^1.3.0",
-        "espree": "^7.2.0",
+        "espree": "^7.3.0",
         "esquery": "^1.2.0",
         "esutils": "^2.0.2",
         "file-entry-cache": "^5.0.1",
@@ -4058,6 +4170,12 @@
           "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
           "dev": true
         },
+        "eslint-visitor-keys": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+          "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+          "dev": true
+        },
         "globals": {
           "version": "12.4.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
@@ -4167,12 +4285,20 @@
       "dev": true,
       "requires": {
         "eslint-visitor-keys": "^1.1.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+          "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+          "dev": true
+        }
       }
     },
     "eslint-visitor-keys": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
-      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
+      "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
       "dev": true
     },
     "espree": {
@@ -4184,6 +4310,14 @@
         "acorn": "^7.4.0",
         "acorn-jsx": "^5.2.0",
         "eslint-visitor-keys": "^1.3.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+          "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+          "dev": true
+        }
       }
     },
     "esprima": {
@@ -4210,12 +4344,20 @@
       }
     },
     "esrecurse": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
-      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
       "dev": true,
       "requires": {
-        "estraverse": "^4.1.0"
+        "estraverse": "^5.2.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+          "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+          "dev": true
+        }
       }
     },
     "estraverse": {
@@ -4530,6 +4672,12 @@
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
       "dev": true
     },
+    "fastest-levenshtein": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
+      "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
+      "dev": true
+    },
     "fastparse": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
@@ -4642,17 +4790,6 @@
         "flatted": "^2.0.0",
         "rimraf": "2.6.3",
         "write": "1.0.3"
-      },
-      "dependencies": {
-        "rimraf": {
-          "version": "2.6.3",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
-          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        }
       }
     },
     "flatted": {
@@ -5584,9 +5721,9 @@
           "dev": true
         },
         "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
           "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
@@ -5722,9 +5859,9 @@
       }
     },
     "lint-staged": {
-      "version": "10.2.13",
-      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.2.13.tgz",
-      "integrity": "sha512-conwlukNV6aL9SiMWjFtDp5exeDnTMekdNPDZsKGnpfQuHcO0E3L3Bbf58lcR+M7vk6LpCilxDAVks/DDVBYlA==",
+      "version": "10.3.0",
+      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.3.0.tgz",
+      "integrity": "sha512-an3VgjHqmJk0TORB/sdQl0CTkRg4E5ybYCXTTCSJ5h9jFwZbcgKIx5oVma5e7wp/uKt17s1QYFmYqT9MGVosGw==",
       "dev": true,
       "requires": {
         "chalk": "^4.1.0",
@@ -5832,15 +5969,6 @@
           "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
           "dev": true
         },
-        "log-symbols": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
-          "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
-          "dev": true,
-          "requires": {
-            "chalk": "^4.0.0"
-          }
-        },
         "micromatch": {
           "version": "4.0.2",
           "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
@@ -5870,9 +5998,9 @@
           "dev": true
         },
         "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
           "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
@@ -5890,9 +6018,9 @@
       }
     },
     "listr2": {
-      "version": "2.6.1",
-      "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.6.1.tgz",
-      "integrity": "sha512-1aPX9GkS+W0aHfPUDedJqeqj0DOe1605NaNoqdwEYw/UF2UbZgCIIMpXXZALeG/8xzwMBztguzQEubU5Xw1Qbw==",
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.6.2.tgz",
+      "integrity": "sha512-6x6pKEMs8DSIpA/tixiYY2m/GcbgMplMVmhQAaLFxEtNSKLeWTGjtmU57xvv6QCm2XcqzyNXL/cTSVf4IChCRA==",
       "dev": true,
       "requires": {
         "chalk": "^4.1.0",
@@ -5956,9 +6084,9 @@
           "dev": true
         },
         "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
           "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
@@ -5998,9 +6126,9 @@
       }
     },
     "lodash": {
-      "version": "4.17.15",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
-      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
+      "version": "4.17.20",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
       "dev": true
     },
     "lodash._reinterpolate": {
@@ -6059,25 +6187,12 @@
       "dev": true
     },
     "log-symbols": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
-      "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
+      "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
       "dev": true,
       "requires": {
-        "chalk": "^2.0.1"
-      },
-      "dependencies": {
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        }
+        "chalk": "^4.0.0"
       }
     },
     "log-update": {
@@ -6111,6 +6226,12 @@
             "color-convert": "^2.0.1"
           }
         },
+        "astral-regex": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+          "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+          "dev": true
+        },
         "cli-cursor": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -7120,16 +7241,16 @@
       }
     },
     "postcss-cli": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-7.1.1.tgz",
-      "integrity": "sha512-bYQy5ydAQJKCMSpvaMg0ThPBeGYqhQXumjbFOmWnL4u65CYXQ16RfS6afGQpit0dGv/fNzxbdDtx8dkqOhhIbg==",
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-7.1.2.tgz",
+      "integrity": "sha512-3mlEmN1v2NVuosMWZM2tP8bgZn7rO5PYxRRrXtdSyL5KipcgBDjJ9ct8/LKxImMCJJi3x5nYhCGFJOkGyEqXBQ==",
       "dev": true,
       "requires": {
         "chalk": "^4.0.0",
         "chokidar": "^3.3.0",
         "dependency-graph": "^0.9.0",
         "fs-extra": "^9.0.0",
-        "get-stdin": "^7.0.0",
+        "get-stdin": "^8.0.0",
         "globby": "^11.0.0",
         "postcss": "^7.0.0",
         "postcss-load-config": "^2.0.0",
@@ -7151,6 +7272,12 @@
             "universalify": "^1.0.0"
           }
         },
+        "get-stdin": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
+          "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+          "dev": true
+        },
         "jsonfile": {
           "version": "6.0.1",
           "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
@@ -8290,6 +8417,15 @@
             "escape-string-regexp": "^1.0.5",
             "supports-color": "^5.3.0"
           }
+        },
+        "log-symbols": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
+          "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==",
+          "dev": true,
+          "requires": {
+            "chalk": "^2.0.1"
+          }
         }
       }
     },
@@ -8593,9 +8729,9 @@
       }
     },
     "prosemirror-view": {
-      "version": "1.15.5",
-      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.15.5.tgz",
-      "integrity": "sha512-VpAP/Rh7a4l1udpR3lEym2FlTD93JZjWChHYgzLgiBI6alOapG4GEsyAEq0l8eUJd9Ujf55+5dlEuItxI3a9Mw==",
+      "version": "1.15.6",
+      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.15.6.tgz",
+      "integrity": "sha512-9FBFB+rK5pvvzHsHOacy0T/Jf+OxZSzY8tSlQiur3SZwAVaNVQm+fl23V/6gU2dHBnreGxjYx9jK+F3XPsPCGw==",
       "requires": {
         "prosemirror-model": "^1.1.0",
         "prosemirror-state": "^1.0.0",
@@ -9009,10 +9145,19 @@
       "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
       "dev": true
     },
+    "rimraf": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+      "dev": true,
+      "requires": {
+        "glob": "^7.1.3"
+      }
+    },
     "rollup": {
-      "version": "2.26.6",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.6.tgz",
-      "integrity": "sha512-iSB7eE3k/VNQHnI7ckS++4yIqTamoUCB1xo7MswhJ/fg22oFYR5+xCrUZVviBj97jvc5A31MPbVMw1Wc3jWxmw==",
+      "version": "2.26.10",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.10.tgz",
+      "integrity": "sha512-dUnjCWOA0h9qNX6qtcHidyatz8FAFZxVxt1dbcGtKdlJkpSxGK3G9+DLCYvtZr9v94D129ij9zUhG+xbRoqepw==",
       "dev": true,
       "requires": {
         "fsevents": "~2.1.2"
@@ -9067,9 +9212,9 @@
       }
     },
     "rollup-plugin-postcss": {
-      "version": "3.1.6",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-3.1.6.tgz",
-      "integrity": "sha512-lkKMTXhPyaNgELFFf7mAGLqFTr13Lswak1YkP+b9rfl6YNVHxs3PYgZFAGLOyLvOtSuCVRq6BryXs1EgyC+nHQ==",
+      "version": "3.1.8",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-postcss/-/rollup-plugin-postcss-3.1.8.tgz",
+      "integrity": "sha512-JHnGfW8quNc6ePxEkZ05HEZ1YiRxDgY9RKEetMfsrwxR2kh/d90OVScTc6b1c2Q17Cs/5TRYL+1uddG21lQe3w==",
       "dev": true,
       "requires": {
         "chalk": "^4.0.0",
@@ -9121,9 +9266,9 @@
       }
     },
     "rollup-plugin-terser": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.0.tgz",
-      "integrity": "sha512-p/N3lLiFusCjYTLfVkoaiRTOGr5AESEaljMPH12MhOtoMkmTBhIAfuadrcWy4am1U0vU4WTxO9fi0K09O4CboQ==",
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.1.tgz",
+      "integrity": "sha512-HL0dgzSxBYG/Ly9i/E5Sc+PuKKZ0zBzk11VmLCfdUtpqH4yYqkLclPkTqRy85FU9246yetImOClaQ/ufnj08vg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.10.4",
@@ -9340,47 +9485,14 @@
       "dev": true
     },
     "slice-ansi": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
-      "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+      "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
       "dev": true,
       "requires": {
-        "ansi-styles": "^4.0.0",
-        "astral-regex": "^2.0.0",
-        "is-fullwidth-code-point": "^3.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        }
+        "ansi-styles": "^3.2.0",
+        "astral-regex": "^1.0.0",
+        "is-fullwidth-code-point": "^2.0.0"
       }
     },
     "snapdragon": {
@@ -9850,19 +9962,21 @@
       }
     },
     "stylelint": {
-      "version": "13.6.1",
-      "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.6.1.tgz",
-      "integrity": "sha512-XyvKyNE7eyrqkuZ85Citd/Uv3ljGiuYHC6UiztTR6sWS9rza8j3UeQv/eGcQS9NZz/imiC4GKdk1EVL3wst5vw==",
+      "version": "13.7.0",
+      "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-13.7.0.tgz",
+      "integrity": "sha512-1wStd4zVetnlHO98VjcHQbjSDmvcA39smkZQMct2cf+hom40H0xlQNdzzbswoG/jGBh61/Ue9m7Lu99PY51O6A==",
       "dev": true,
       "requires": {
-        "@stylelint/postcss-css-in-js": "^0.37.1",
+        "@stylelint/postcss-css-in-js": "^0.37.2",
         "@stylelint/postcss-markdown": "^0.36.1",
-        "autoprefixer": "^9.8.0",
+        "autoprefixer": "^9.8.6",
         "balanced-match": "^1.0.0",
         "chalk": "^4.1.0",
-        "cosmiconfig": "^6.0.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",
@@ -9873,18 +9987,16 @@
         "import-lazy": "^4.0.0",
         "imurmurhash": "^0.1.4",
         "known-css-properties": "^0.19.0",
-        "leven": "^3.1.0",
-        "lodash": "^4.17.15",
+        "lodash": "^4.17.20",
         "log-symbols": "^4.0.0",
         "mathml-tag-names": "^2.1.3",
-        "meow": "^7.0.1",
+        "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-reporter": "^6.0.1",
         "postcss-resolve-nested-selector": "^0.1.1",
         "postcss-safe-parser": "^4.0.2",
         "postcss-sass": "^0.4.4",
@@ -9900,7 +10012,7 @@
         "style-search": "^0.1.0",
         "sugarss": "^2.0.0",
         "svg-tags": "^1.0.0",
-        "table": "^5.4.6",
+        "table": "^6.0.1",
         "v8-compile-cache": "^2.1.1",
         "write-file-atomic": "^3.0.3"
       },
@@ -9921,6 +10033,27 @@
             "color-convert": "^2.0.1"
           }
         },
+        "astral-regex": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+          "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+          "dev": true
+        },
+        "autoprefixer": {
+          "version": "9.8.6",
+          "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
+          "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
+          "dev": true,
+          "requires": {
+            "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"
+          }
+        },
         "braces": {
           "version": "3.0.2",
           "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
@@ -9930,6 +10063,12 @@
             "fill-range": "^7.0.1"
           }
         },
+        "caniuse-lite": {
+          "version": "1.0.30001124",
+          "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001124.tgz",
+          "integrity": "sha512-zQW8V3CdND7GHRH6rxm6s59Ww4g/qGWTheoboW9nfeMg7sUoopIfKCcNZUjwYRCOrvereh3kwDpZj4VLQ7zGtA==",
+          "dev": true
+        },
         "chalk": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
@@ -9956,25 +10095,30 @@
           "dev": true
         },
         "cosmiconfig": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz",
-          "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==",
+          "version": "7.0.0",
+          "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+          "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
           "dev": true,
           "requires": {
             "@types/parse-json": "^4.0.0",
-            "import-fresh": "^3.1.0",
+            "import-fresh": "^3.2.1",
             "parse-json": "^5.0.0",
             "path-type": "^4.0.0",
-            "yaml": "^1.7.2"
+            "yaml": "^1.10.0"
           }
         },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+        "fast-glob": {
+          "version": "3.2.4",
+          "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
+          "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
           "dev": true,
           "requires": {
-            "ms": "^2.1.1"
+            "@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"
           }
         },
         "fill-range": {
@@ -10048,28 +10192,23 @@
           "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
           "dev": true
         },
-        "log-symbols": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
-          "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
-          "dev": true,
-          "requires": {
-            "chalk": "^4.0.0"
-          }
+        "lodash": {
+          "version": "4.17.20",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+          "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+          "dev": true
         },
         "meow": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz",
-          "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==",
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz",
+          "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==",
           "dev": true,
           "requires": {
             "@types/minimist": "^1.2.0",
-            "arrify": "^2.0.1",
-            "camelcase": "^6.0.0",
             "camelcase-keys": "^6.2.2",
             "decamelize-keys": "^1.1.0",
             "hard-rejection": "^2.1.0",
-            "minimist-options": "^4.0.2",
+            "minimist-options": "4.1.0",
             "normalize-package-data": "^2.5.0",
             "read-pkg-up": "^7.0.1",
             "redent": "^3.0.0",
@@ -10088,21 +10227,15 @@
             "picomatch": "^2.0.5"
           }
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
         "parse-json": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz",
-          "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==",
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz",
+          "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==",
           "dev": true,
           "requires": {
             "@babel/code-frame": "^7.0.0",
             "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1",
+            "json-parse-even-better-errors": "^2.3.0",
             "lines-and-columns": "^1.1.6"
           }
         },
@@ -10112,6 +10245,17 @@
           "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
           "dev": true
         },
+        "slice-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+          "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "astral-regex": "^2.0.0",
+            "is-fullwidth-code-point": "^3.0.0"
+          }
+        },
         "string-width": {
           "version": "4.2.0",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@@ -10133,14 +10277,26 @@
           }
         },
         "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
           "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
           }
         },
+        "table": {
+          "version": "6.0.3",
+          "resolved": "https://registry.npmjs.org/table/-/table-6.0.3.tgz",
+          "integrity": "sha512-8321ZMcf1B9HvVX/btKv8mMZahCjn2aYrDlpqHaBFCfnox64edeH9kEid0vTLTRR8gWR2A20aDgeuTTea4sVtw==",
+          "dev": true,
+          "requires": {
+            "ajv": "^6.12.4",
+            "lodash": "^4.17.20",
+            "slice-ansi": "^4.0.0",
+            "string-width": "^4.2.0"
+          }
+        },
         "to-regex-range": {
           "version": "5.0.1",
           "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -10237,29 +10393,12 @@
         "string-width": "^3.0.0"
       },
       "dependencies": {
-        "astral-regex": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
-          "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
-          "dev": true
-        },
         "emoji-regex": {
           "version": "7.0.3",
           "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
           "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
           "dev": true
         },
-        "slice-ansi": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
-          "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.0",
-            "astral-regex": "^1.0.0",
-            "is-fullwidth-code-point": "^2.0.0"
-          }
-        },
         "string-width": {
           "version": "3.1.0",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
@@ -10274,9 +10413,9 @@
       }
     },
     "tailwindcss": {
-      "version": "1.7.5",
-      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.7.5.tgz",
-      "integrity": "sha512-thDHLkRioJh0/62EFcEfQCCBEsZXpluehymrPzn8Hkycy8uI9svvtOqyWtcfkBPB0s5yb6R2tY9zPzh5mIr0Wg==",
+      "version": "1.7.6",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.7.6.tgz",
+      "integrity": "sha512-focAhU3ciM1/UYBHQVKKzede4zC3y9+IHzU2N/ZF6mbZbhY8S96lOxrO2Y6LMU08+Dbh2xBLmO1bsioLk3Egig==",
       "dev": true,
       "requires": {
         "@fullhuman/postcss-purgecss": "^2.1.2",
@@ -10311,9 +10450,9 @@
       }
     },
     "terser": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.2.1.tgz",
-      "integrity": "sha512-/AOtjRtAMNGO0fIF6m8HfcvXTw/2AKpsOzDn36tA5RfhRdeXyb4RvHxJ5Pah7iL6dFkLk+gOnCaNHGwJPl6TrQ==",
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz",
+      "integrity": "sha512-XTT3D3AwxC54KywJijmY2mxZ8nJiEjBHVYzq8l9OaYuRFWeQNBwvipuzzYEP4e+/AVcd1hqG/CqgsdIRyT45Fg==",
       "dev": true,
       "requires": {
         "commander": "^2.20.0",
@@ -10551,9 +10690,9 @@
       "dev": true
     },
     "unified": {
-      "version": "9.1.0",
-      "resolved": "https://registry.npmjs.org/unified/-/unified-9.1.0.tgz",
-      "integrity": "sha512-VXOv7Ic6twsKGJDeZQ2wwPqXs2hM0KNu5Hkg9WgAZbSD1pxhZ7p8swqg583nw1Je2fhwHy6U8aEjiI79x1gvag==",
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
+      "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
       "dev": true,
       "requires": {
         "bail": "^1.0.0",
@@ -10709,9 +10848,9 @@
       }
     },
     "uri-js": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
-      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+      "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
       "dev": true,
       "requires": {
         "punycode": "^2.1.0"
@@ -10770,9 +10909,9 @@
       "dev": true
     },
     "vfile": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.1.1.tgz",
-      "integrity": "sha512-lRjkpyDGjVlBA7cDQhQ+gNcvB1BGaTHYuSOcY3S7OhDmBtnzX95FhtZZDecSTDm6aajFymyve6S5DN4ZHGezdQ==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.0.tgz",
+      "integrity": "sha512-a/alcwCvtuc8OX92rqqo7PflxiCgXRFjdyoGVuYV+qbgCb0GgZJRvIgCD4+U/Kl1yhaRsaTwksF88xbPyGsgpw==",
       "dev": true,
       "requires": {
         "@types/unist": "^2.0.0",
@@ -10791,9 +10930,9 @@
       }
     },
     "vfile-location": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.0.1.tgz",
-      "integrity": "sha512-yYBO06eeN/Ki6Kh1QAkgzYpWT1d3Qln+ZCtSbJqFExPl1S3y2qqotJQXoh6qEvl/jDlgpUJolBn3PItVnnZRqQ==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.1.0.tgz",
+      "integrity": "sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g==",
       "dev": true
     },
     "vfile-message": {
diff --git a/package.json b/package.json
index 7b4b8c4ff2cde01342cace20d89d40185a3e2b7b..258cb74f7a27b42df843bd5d9245fdc116d20f59 100644
--- a/package.json
+++ b/package.json
@@ -29,12 +29,12 @@
     "prosemirror-example-setup": "^1.1.2",
     "prosemirror-markdown": "^1.5.0",
     "prosemirror-state": "^1.3.3",
-    "prosemirror-view": "^1.15.5"
+    "prosemirror-view": "^1.15.6"
   },
   "devDependencies": {
-    "@babel/core": "^7.11.4",
+    "@babel/core": "^7.11.6",
     "@babel/plugin-proposal-class-properties": "^7.10.4",
-    "@babel/preset-env": "^7.11.0",
+    "@babel/preset-env": "^7.11.5",
     "@babel/preset-typescript": "^7.10.4",
     "@commitlint/cli": "^9.1.2",
     "@commitlint/config-conventional": "^9.1.2",
@@ -49,30 +49,30 @@
     "@types/codemirror": "0.0.97",
     "@types/prosemirror-markdown": "^1.0.3",
     "@types/prosemirror-view": "^1.15.1",
-    "@typescript-eslint/eslint-plugin": "^3.10.1",
-    "@typescript-eslint/parser": "^3.10.1",
+    "@typescript-eslint/eslint-plugin": "^4.0.1",
+    "@typescript-eslint/parser": "^4.0.1",
     "cross-env": "^7.0.2",
     "cssnano": "^4.1.10",
     "cz-conventional-changelog": "^3.3.0",
-    "eslint": "^7.7.0",
+    "eslint": "^7.8.1",
     "eslint-config-prettier": "^6.11.0",
     "eslint-plugin-prettier": "^3.1.4",
     "husky": "^4.2.5",
-    "lint-staged": "^10.2.13",
-    "postcss-cli": "^7.1.1",
+    "lint-staged": "^10.3.0",
+    "postcss-cli": "^7.1.2",
     "postcss-import": "^12.0.1",
     "postcss-preset-env": "^6.7.0",
     "prettier": "2.1.1",
     "prettier-plugin-organize-imports": "^1.1.1",
-    "rollup": "^2.26.6",
+    "rollup": "^2.26.10",
     "rollup-plugin-multi-input": "^1.1.1",
     "rollup-plugin-node-polyfills": "^0.2.1",
-    "rollup-plugin-postcss": "^3.1.6",
-    "rollup-plugin-terser": "^7.0.0",
-    "stylelint": "^13.6.1",
+    "rollup-plugin-postcss": "^3.1.8",
+    "rollup-plugin-terser": "^7.0.1",
+    "stylelint": "^13.7.0",
     "stylelint-config-standard": "^20.0.0",
     "svgo": "^1.3.2",
-    "tailwindcss": "^1.7.5",
+    "tailwindcss": "^1.7.6",
     "typescript": "^4.0.2"
   },
   "husky": {
diff --git a/public/.htaccess b/public/.htaccess
index 699e1c1fc84e32e67c81085c28b678c5f9c2c621..7606ab4861659d9bd4953a5e86e11558c08af73d 100644
--- a/public/.htaccess
+++ b/public/.htaccess
@@ -18,7 +18,8 @@ Options All -Indexes
 
 	# Redirect Trailing Slashes...
 	RewriteCond %{REQUEST_FILENAME} !-d
-    	RewriteRule ^(.*)/$ /$1 [L,R=301]
+	RewriteCond %{REQUEST_URI} (.+)/$
+      RewriteRule ^ %1 [L,R=301]
 
 	# Rewrite "www.example.com -> example.com"
 	RewriteCond %{HTTPS} !=on
@@ -30,7 +31,7 @@ Options All -Indexes
     # request to the front controller, index.php
 	RewriteCond %{REQUEST_FILENAME} !-f
 	RewriteCond %{REQUEST_FILENAME} !-d
-	RewriteRule ^(.*)$ index.php/$1 [L]
+	RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
 
 	# Ensure Authorization header is passed along
     RewriteCond %{HTTP:Authorization} .
@@ -45,4 +46,4 @@ Options All -Indexes
 
 # Disable server signature start
     ServerSignature Off
-# Disable server signature end
+# Disable server signature end
\ No newline at end of file