]> Untitled Git - lemmy-ui.git/commitdiff
Merge branch 'fix/notif_new_fetch_bug' of https://github.com/ernestwisniewski/lemmy...
authorDessalines <tyhou13@gmx.com>
Wed, 21 Sep 2022 14:16:54 +0000 (10:16 -0400)
committerDessalines <tyhou13@gmx.com>
Wed, 21 Sep 2022 14:16:54 +0000 (10:16 -0400)
94 files changed:
.drone.yml
.eslintrc.json
.github/CODEOWNERS [new file with mode: 0644]
.github/ISSUE_TEMPLATE/hexbear.md [new file with mode: 0644]
README.md
deploy.sh
lemmy-translations
package.json
src/assets/css/main.css
src/assets/css/themes/cyborg.css [moved from src/assets/css/themes/cyborg.min.css with 100% similarity]
src/assets/css/themes/darkly-red.css [new file with mode: 0644]
src/assets/css/themes/darkly.css [new file with mode: 0644]
src/assets/css/themes/darkly.min.css [deleted file]
src/assets/css/themes/i386.css [moved from src/assets/css/themes/i386.min.css with 100% similarity]
src/assets/css/themes/journal.css [moved from src/assets/css/themes/journal.min.css with 100% similarity]
src/assets/css/themes/litely-red.css [new file with mode: 0644]
src/assets/css/themes/litely.css [moved from src/assets/css/themes/litely.min.css with 100% similarity]
src/assets/css/themes/litera.css [moved from src/assets/css/themes/litera.min.css with 100% similarity]
src/assets/css/themes/materia.css [moved from src/assets/css/themes/materia.min.css with 100% similarity]
src/assets/css/themes/minty.css [moved from src/assets/css/themes/minty.min.css with 100% similarity]
src/assets/css/themes/nord.css [new file with mode: 0644]
src/assets/css/themes/sketchy.css [moved from src/assets/css/themes/sketchy.min.css with 100% similarity]
src/assets/css/themes/solar.css [moved from src/assets/css/themes/solar.min.css with 100% similarity]
src/assets/css/themes/united.css [moved from src/assets/css/themes/united.min.css with 100% similarity]
src/assets/css/themes/vaporwave-dark.css [moved from src/assets/css/themes/vaporwave-dark.min.css with 100% similarity]
src/assets/css/themes/vaporwave.css [moved from src/assets/css/themes/vaporwave.min.css with 100% similarity]
src/client/index.tsx
src/server/index.tsx
src/shared/components/app/app.tsx
src/shared/components/app/footer.tsx
src/shared/components/app/navbar.tsx
src/shared/components/app/theme.tsx
src/shared/components/comment/comment-form.tsx
src/shared/components/comment/comment-node.tsx
src/shared/components/comment/comment-nodes.tsx
src/shared/components/comment/comment-report.tsx [new file with mode: 0644]
src/shared/components/common/banner-icon-header.tsx
src/shared/components/common/comment-sort-select.tsx [new file with mode: 0644]
src/shared/components/common/html-tags.tsx
src/shared/components/common/icon.tsx
src/shared/components/common/image-upload-form.tsx
src/shared/components/common/listing-type-select.tsx
src/shared/components/common/markdown-textarea.tsx
src/shared/components/common/moment-time.tsx
src/shared/components/common/pictrs-image.tsx
src/shared/components/common/registration-application.tsx [new file with mode: 0644]
src/shared/components/common/sort-select.tsx
src/shared/components/common/symbols.tsx
src/shared/components/community/communities.tsx
src/shared/components/community/community-form.tsx
src/shared/components/community/community-link.tsx
src/shared/components/community/community.tsx
src/shared/components/community/create-community.tsx
src/shared/components/community/sidebar.tsx
src/shared/components/home/admin-settings.tsx
src/shared/components/home/home.tsx
src/shared/components/home/instances.tsx
src/shared/components/home/legal.tsx [new file with mode: 0644]
src/shared/components/home/login.tsx
src/shared/components/home/setup.tsx
src/shared/components/home/signup.tsx [new file with mode: 0644]
src/shared/components/home/site-form.tsx
src/shared/components/home/site-sidebar.tsx [new file with mode: 0644]
src/shared/components/modlog.tsx
src/shared/components/person/inbox.tsx
src/shared/components/person/password-change.tsx [moved from src/shared/components/home/password_change.tsx with 90% similarity]
src/shared/components/person/person-details.tsx
src/shared/components/person/person-listing.tsx
src/shared/components/person/profile.tsx
src/shared/components/person/registration-applications.tsx [new file with mode: 0644]
src/shared/components/person/reports.tsx [new file with mode: 0644]
src/shared/components/person/settings.tsx
src/shared/components/person/verify-email.tsx [new file with mode: 0644]
src/shared/components/post/create-post.tsx
src/shared/components/post/metadata-card.tsx
src/shared/components/post/post-form.tsx
src/shared/components/post/post-listing.tsx
src/shared/components/post/post-listings.tsx
src/shared/components/post/post-report.tsx [new file with mode: 0644]
src/shared/components/post/post.tsx
src/shared/components/private_message/create-private-message.tsx
src/shared/components/private_message/private-message-form.tsx
src/shared/components/private_message/private-message.tsx
src/shared/components/search.tsx
src/shared/env.ts
src/shared/i18next.ts
src/shared/interfaces.ts
src/shared/routes.ts
src/shared/services/UserService.ts
src/shared/services/WebSocketService.ts
src/shared/utils.ts
tsconfig.json
webpack.config.js
yarn.lock

index bfb6ab7a94f4a0b6fbdefe595b308c9c261f5f52..049a47884375a5ca05b37798bf16f7be0e35483a 100644 (file)
@@ -31,37 +31,20 @@ steps:
     commands:
       - yarn build:dev
 
-  - name: publish dev docker image
+  - name: nightly build
     image: plugins/docker
     settings:
       dockerfile: Dockerfile
       repo: dessalines/lemmy-ui
-      tags:
-        - dev-linux-amd64
-      username:
-        from_secret: docker_username
-      password:
-        from_secret: docker_password
-    when:
-      ref:
-        - refs/heads/main
-
-  - name: publish dev docker manifest
-    image: plugins/manifest
-    settings:
       username:
         from_secret: docker_username
       password:
         from_secret: docker_password
-      target: "dessalines/lemmy-ui:dev"
-      template: "dessalines/lemmy-ui:dev-OS-ARCH"
-      platforms:
-        - linux/amd64
-        - linux/arm64
-      ignore_missing: true
+      tags:
+        - dev
     when:
-      ref:
-        - refs/heads/main
+      event:
+        - cron
 
   - name: publish release docker image
     image: plugins/docker
@@ -95,6 +78,23 @@ steps:
       ref:
       - refs/tags/*
 
+  - name: publish latest release docker manifest
+    image: plugins/manifest
+    settings: 
+      username:
+        from_secret: docker_username
+      password:
+        from_secret: docker_password
+      target: "dessalines/lemmy-ui:latest"
+      template: "dessalines/lemmy-ui:${DRONE_TAG}-OS-ARCH"
+      platforms:
+        - linux/amd64
+        - linux/arm64
+      ignore_missing: true
+    when:
+      ref:
+      - refs/tags/*
+
 ---
 kind: pipeline
 name: arm64
@@ -117,61 +117,46 @@ steps:
         - refs/heads/main
         - refs/tags/*
 
-  - name: publish dev docker image
+  - name: publish release docker image
     image: plugins/docker
     settings:
       dockerfile: Dockerfile
       repo: dessalines/lemmy-ui
-      tags:
-        - dev-linux-arm64
+      auto_tag: true
+      auto_tag_suffix: linux-arm64
       username:
         from_secret: docker_username
       password:
         from_secret: docker_password
     when:
       ref:
-        - refs/heads/main
+        - refs/tags/*
 
-  - name: publish dev docker manifest
+  - name: publish release docker manifest
     image: plugins/manifest
-    settings:
+    settings: 
       username:
         from_secret: docker_username
       password:
         from_secret: docker_password
-      target: "dessalines/lemmy-ui:dev"
-      template: "dessalines/lemmy-ui:dev-OS-ARCH"
+      target: "dessalines/lemmy-ui:${DRONE_TAG}"
+      template: "dessalines/lemmy-ui:${DRONE_TAG}-OS-ARCH"
       platforms:
         - linux/amd64
         - linux/arm64
       ignore_missing: true
     when:
       ref:
-        - refs/heads/main
-
-  - name: publish release docker image
-    image: plugins/docker
-    settings:
-      dockerfile: Dockerfile
-      repo: dessalines/lemmy-ui
-      auto_tag: true
-      auto_tag_suffix: linux-arm64
-      username:
-        from_secret: docker_username
-      password:
-        from_secret: docker_password
-    when:
-      ref:
-        - refs/tags/*
+      - refs/tags/*
 
-  - name: publish release docker manifest
+  - name: publish latest release docker manifest
     image: plugins/manifest
     settings: 
       username:
         from_secret: docker_username
       password:
         from_secret: docker_password
-      target: "dessalines/lemmy-ui:${DRONE_TAG}"
+      target: "dessalines/lemmy-ui:latest"
       template: "dessalines/lemmy-ui:${DRONE_TAG}-OS-ARCH"
       platforms:
         - linux/amd64
index 093a700c196e1a2e045af30017e21beb7068f338..4e05f0c5a73bf41a8da67062d94fe3953d2648cd 100644 (file)
@@ -16,6 +16,7 @@
     "warnOnUnsupportedTypeScriptVersion": false
   },
   "rules": {
+    "@typescript-eslint/ban-ts-comment": 0,
     "@typescript-eslint/no-explicit-any": 0,
     "@typescript-eslint/explicit-module-boundary-types": 0,
     "arrow-body-style": 0,
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644 (file)
index 0000000..983e6c2
--- /dev/null
@@ -0,0 +1 @@
+* @dessalines
diff --git a/.github/ISSUE_TEMPLATE/hexbear.md b/.github/ISSUE_TEMPLATE/hexbear.md
new file mode 100644 (file)
index 0000000..3bb0623
--- /dev/null
@@ -0,0 +1,10 @@
+---
+name: Hexbear
+about: For hexbear issues
+title: ''
+labels: hexbear
+assignees: ''
+
+---
+
+For hexbear-related issues
index a6969d03a45f56995784c92e6031d496d7f3a18b..e1e6e1fda2e8051367d01ecc79eb9b5ff02fd612 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,3 +3,19 @@
 The official web app for [Lemmy](https://github.com/LemmyNet/lemmy), written in inferno.\r
 \r
 Based off of MrFoxPro's [inferno-isomorphic-template](https://github.com/MrFoxPro/inferno-isomorphic-template).\r
+\r
+## Configuration\r
+\r
+The following environment variables can be used to configure lemmy-ui:\r
+\r
+`ENV_VAR` | type | default | description\r
+--- | --- | --- | ---\r
+`LEMMY_UI_HOST` | `string` | `0.0.0.0:1234` | The IP / port that the lemmy-ui isomorphic node server is hosted at.\r
+`LEMMY_UI_LEMMY_INTERNAL_HOST` | `string` | `0.0.0.0:8536` | The internal IP / port that lemmy is hosted at. Often `lemmy:8536` if using docker.\r
+`LEMMY_UI_LEMMY_EXTERNAL_HOST` | `string` | `0.0.0.0:8536` | The external IP / port that lemmy is hosted at. Often `DOMAIN.TLD`.\r
+`LEMMY_UI_LEMMY_WS_HOST` | `string` | `0.0.0.0:8536` | An alternate location for lemmy's websocket address. Not usually necessary.\r
+`LEMMY_UI_HTTPS` | `bool` | `false` | Whether to use https.\r
+`LEMMY_UI_EXTRA_THEMES_FOLDER` | `string` | `./extra_themes` | A location for additional lemmy css themes.\r
+`LEMMY_UI_DEBUG` | `bool` | `false` | Loads the [Eruda](https://github.com/liriliri/eruda) debugging utility.\r
+`LEMMY_UI_DISABLE_CSP` | `bool` | `false` | Disables CSP security headers\r
+`LEMMY_UI_CUSTOM_HTML_HEADER` | `string` | | Injects a custom script into `<head>`.\r
index 57aa818910e8926686a893bae53cafc675a677b0..ce125fcd7f994a0e28c554311c5cb1120439c322 100755 (executable)
--- a/deploy.sh
+++ b/deploy.sh
@@ -7,5 +7,9 @@ new_tag="$1"
 # sudo docker build . --tag dessalines/lemmy-ui:$new_tag
 # sudo docker push dessalines/lemmy-ui:$new_tag
 
+# Upgrade version
+yarn version --new-version $new_tag
+git push
+
 git tag $new_tag
 git push origin $new_tag
index eee933bd87780e0e2a8700e9b8fe0047f14f428a..7ac48ae98271b3b573e28c90b87f9704492e0b62 160000 (submodule)
@@ -1 +1 @@
-Subproject commit eee933bd87780e0e2a8700e9b8fe0047f14f428a
+Subproject commit 7ac48ae98271b3b573e28c90b87f9704492e0b62
index 28620114ad14d286441fa442f476c858e0bb5a1a..a430314b31de4333fac7cd64c44dd2f6ffdf5fc5 100644 (file)
@@ -1,6 +1,7 @@
 {
   "name": "lemmy-ui",
   "description": "An isomorphic UI for lemmy",
+  "version": "0.16.5",
   "author": "Dessalines <tyhou13@gmx.com>",
   "license": "AGPL-3.0",
   "scripts": {
     "lint": "node generate_translations.js && tsc --noEmit && eslint --report-unused-disable-directives --ext .js,.ts,.tsx src",
     "prebuild:dev": "yarn clean && node generate_translations.js",
     "prebuild:prod": "yarn clean && node generate_translations.js",
+    "prepare": "husky install",
     "start": "yarn build:dev --watch"
   },
   "repository": "https://github.com/LemmyNet/lemmy-ui",
   "dependencies": {
-    "@typescript-eslint/parser": "^4.28.3",
+    "@typescript-eslint/parser": "^5.31.0",
     "autosize": "^5.0.1",
-    "choices.js": "^9.0.1",
-    "emoji-short-name": "^1.0.0",
-    "express": "~4.17.1",
-    "i18next": "^20.3.3",
-    "inferno": "^7.4.9",
-    "inferno-create-element": "^7.4.9",
+    "check-password-strength": "^2.0.7",
+    "choices.js": "^10.1.0",
+    "classnames": "^2.3.1",
+    "emoji-short-name": "^2.0.0",
+    "express": "~4.18.1",
+    "i18next": "^21.8.14",
+    "inferno": "^7.4.11",
+    "inferno-create-element": "^7.4.11",
     "inferno-helmet": "^5.2.1",
-    "inferno-hydrate": "^7.4.9",
-    "inferno-i18next": "github:nimbusec-oss/inferno-i18next#semver:^7.4.2",
-    "inferno-router": "^7.4.9",
-    "inferno-server": "^7.4.9",
+    "inferno-hydrate": "^7.4.11",
+    "inferno-i18next-dess": "^0.0.1",
+    "inferno-router": "^7.4.11",
+    "inferno-server": "^7.4.11",
     "isomorphic-cookie": "^1.2.4",
     "jwt-decode": "^3.1.2",
-    "markdown-it": "^12.1.0",
+    "markdown-it": "^13.0.1",
     "markdown-it-container": "^3.0.0",
+    "markdown-it-footnote": "^3.0.3",
+    "markdown-it-html5-embed": "^1.0.0",
     "markdown-it-sub": "^1.0.0",
     "markdown-it-sup": "^1.0.0",
-    "moment": "^2.29.1",
-    "reconnecting-websocket": "^4.4.0",
+    "moment": "^2.29.4",
     "register-service-worker": "^1.7.2",
-    "rxjs": "^7.2.0",
+    "rxjs": "^7.5.6",
+    "sass": "^1.54.0",
     "serialize-javascript": "^6.0.0",
-    "tippy.js": "^6.3.1",
-    "toastify-js": "^1.11.1",
+    "tippy.js": "^6.3.7",
+    "toastify-js": "^1.12.0",
     "tributejs": "^5.1.3",
-    "ws": "^8.2.0"
+    "websocket-ts": "^1.1.1"
   },
   "devDependencies": {
-    "@babel/core": "^7.14.6",
-    "@babel/plugin-transform-runtime": "^7.14.5",
-    "@babel/plugin-transform-typescript": "^7.14.6",
-    "@babel/preset-env": "7.15.0",
-    "@babel/preset-typescript": "^7.14.5",
-    "@babel/runtime": "^7.14.6",
+    "@babel/core": "^7.18.9",
+    "@babel/plugin-proposal-decorators": "^7.18.9",
+    "@babel/plugin-transform-runtime": "^7.18.9",
+    "@babel/plugin-transform-typescript": "^7.18.8",
+    "@babel/preset-env": "7.18.9",
+    "@babel/preset-typescript": "^7.18.6",
+    "@babel/runtime": "^7.18.9",
+    "@sniptt/monads": "^0.5.10",
     "@types/autosize": "^4.0.0",
     "@types/express": "^4.17.13",
-    "@types/node": "^16.7.1",
-    "@types/node-fetch": "^2.5.11",
+    "@types/node": "^18.6.2",
+    "@types/node-fetch": "^2.6.2",
     "@types/serialize-javascript": "^5.0.1",
-    "@typescript-eslint/eslint-plugin": "^4.28.3",
-    "babel-loader": "^8.2.2",
-    "babel-plugin-inferno": "^6.3.0",
-    "bootstrap": "^5.0.2",
-    "bootswatch": "^5.0.2",
-    "clean-webpack-plugin": "^4.0.0-alpha.0",
-    "copy-webpack-plugin": "^9.0.1",
-    "css-loader": "^6.0.0",
-    "eslint": "^7.30.0",
-    "eslint-plugin-prettier": "^3.4.1",
-    "husky": "^7.0.1",
+    "@typescript-eslint/eslint-plugin": "^5.31.0",
+    "babel-loader": "^8.2.5",
+    "babel-plugin-inferno": "^6.5.0",
+    "bootstrap": "^5.2.0",
+    "bootswatch": "^5.2.0",
+    "class-transformer": "^0.5.1",
+    "clean-webpack-plugin": "^4.0.0",
+    "copy-webpack-plugin": "^11.0.0",
+    "css-loader": "^6.7.1",
+    "eslint": "^8.20.0",
+    "eslint-plugin-prettier": "^4.2.1",
+    "husky": "^8.0.1",
     "import-sort-style-module": "^6.0.0",
-    "iso-639-1": "^2.1.9",
-    "lemmy-js-client": "0.12.0",
-    "lint-staged": "^11.0.1",
-    "mini-css-extract-plugin": "^2.1.0",
+    "lemmy-js-client": "0.17.0-rc.43",
+    "lint-staged": "^13.0.3",
+    "mini-css-extract-plugin": "^2.6.1",
     "node-fetch": "^2.6.1",
-    "node-sass": "^6.0.1",
-    "prettier": "^2.3.2",
+    "prettier": "^2.7.1",
     "prettier-plugin-import-sort": "^0.0.7",
-    "prettier-plugin-organize-imports": "^2.2.0",
-    "prettier-plugin-packagejson": "^2.2.11",
+    "prettier-plugin-organize-imports": "^3.0.0",
+    "prettier-plugin-packagejson": "^2.2.18",
+    "reflect-metadata": "^0.1.13",
     "rimraf": "^3.0.2",
     "run-node-webpack-plugin": "^1.3.0",
-    "sass-loader": "^12.1.0",
-    "sortpack": "^2.2.0",
-    "style-loader": "^3.1.0",
-    "terser": "^5.7.1",
-    "typescript": "^4.3.5",
-    "webpack": "5.51.1",
-    "webpack-cli": "^4.7.2",
-    "webpack-dev-server": "4.0.0",
+    "sass-loader": "^13.0.2",
+    "sortpack": "^2.3.0",
+    "style-loader": "^3.3.1",
+    "terser": "^5.14.2",
+    "typescript": "^4.7.4",
+    "webpack": "5.74.0",
+    "webpack-cli": "^4.10.0",
+    "webpack-dev-server": "4.9.3",
     "webpack-node-externals": "^3.0.0"
   },
   "engines": {
index ef6b743d3c7f3211b6aa4b424a4920ee556b572e..3ec52d0a6cabc747adfbe4ebaa401086e48bd441 100644 (file)
 }
 
 .icon {
+  display: inline-grid;
   display: inline-flex;
   width: 1em;
   height: 1em;
 }
 
 .spinner-large {
+  display: grid;
   display: block;
   margin: 1em auto;
   width: 2em;
@@ -207,6 +209,10 @@ hr {
   text-overflow: ellipsis;
 }
 
+.overflow-wrap-anywhere {
+  overflow-wrap: anywhere;
+}
+
 #app {
   display: flex;
   flex-direction: column;
@@ -360,3 +366,23 @@ br.big {
 .tribute-container .menu-highlighted {
   font-weight: bold;
 }
+
+.honeypot {
+  display:none !important;
+}
+
+.slight-radius {
+  border-radius: 4px;
+}
+
+.modlog-choices-font-size {
+  font-size: .9375rem !important;
+}
+
+.preview-lines {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-line-clamp: 3;
+  -webkit-box-orient: vertical;
+}
diff --git a/src/assets/css/themes/darkly-red.css b/src/assets/css/themes/darkly-red.css
new file mode 100644 (file)
index 0000000..bb594f0
--- /dev/null
@@ -0,0 +1,8811 @@
+:root {
+ --blue:#375a7f;
+ --indigo:#6610f2;
+ --purple:#6f42c1;
+ --pink:#e83e8c;
+ --red:#e74c3c;
+ --orange:#fd7e14;
+ --yellow:#f39c12;
+ --green:#00bc8c;
+ --teal:#20c997;
+ --cyan:#3498db;
+ --white:#fff;
+ --gray:#888;
+ --gray-dark:#303030;
+ --primary:#375a7f;
+ --secondary:#444;
+ --success:#00bc8c;
+ --info:#3498db;
+ --warning:#f39c12;
+ --danger:#e74c3c;
+ --light:#303030;
+ --dark:#dee2e6;
+ --breakpoint-xs:0;
+ --breakpoint-sm:576px;
+ --breakpoint-md:768px;
+ --breakpoint-lg:992px;
+ --breakpoint-xl:1200px;
+ --font-family-sans-serif:"Lato",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
+ --font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace
+}
+*,
+::after,
+::before {
+ box-sizing:border-box
+}
+html {
+ font-family:sans-serif;
+ line-height:1.15;
+ -webkit-text-size-adjust:100%;
+ -webkit-tap-highlight-color:transparent
+}
+article,
+aside,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section {
+ display:block
+}
+body {
+ margin:0;
+ font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Cantarell,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
+ font-size:.9375rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#dee2e6;
+ text-align:left;
+ background-color:#222
+}
+[tabindex="-1"]:focus:not(:focus-visible) {
+ outline:0!important
+}
+hr {
+ box-sizing:content-box;
+ height:0;
+ overflow:visible
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-top:0;
+ margin-bottom:.5rem
+}
+p {
+ margin-top:0;
+ margin-bottom:1rem
+}
+abbr[data-original-title],
+abbr[title] {
+ text-decoration:underline;
+ text-decoration:underline dotted;
+ cursor:help;
+ border-bottom:0;
+ text-decoration-skip-ink:none
+}
+address {
+ margin-bottom:1rem;
+ font-style:normal;
+ line-height:inherit
+}
+dl,
+ol,
+ul {
+ margin-top:0;
+ margin-bottom:1rem
+}
+ol ol,
+ol ul,
+ul ol,
+ul ul {
+ margin-bottom:0
+}
+dt {
+ font-weight:700
+}
+dd {
+ margin-bottom:.5rem;
+ margin-left:0
+}
+blockquote {
+ margin:0 0 1rem
+}
+b,
+strong {
+ font-weight:bolder
+}
+small {
+ font-size:80%
+}
+sub,
+sup {
+ position:relative;
+ font-size:75%;
+ line-height:0;
+ vertical-align:baseline
+}
+sub {
+ bottom:-.25em
+}
+sup {
+ top:-.5em
+}
+a {
+ color:#e74c3c;
+ text-decoration:none;
+ background-color:transparent
+}
+a:hover {
+ color:#a62f22;
+ text-decoration:underline
+}
+a:not([href]) {
+ color:inherit;
+ text-decoration:none
+}
+a:not([href]):hover {
+ color:inherit;
+ text-decoration:none
+}
+code,
+kbd,
+pre,
+samp {
+ font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size:1em
+}
+pre {
+ margin-top:0;
+ margin-bottom:1rem;
+ overflow:auto;
+ -ms-overflow-style:scrollbar
+}
+figure {
+ margin:0 0 1rem
+}
+img {
+ vertical-align:middle;
+ border-style:none
+}
+svg {
+ overflow:hidden;
+ vertical-align:middle
+}
+table {
+ border-collapse:collapse
+}
+caption {
+ padding-top:.75rem;
+ padding-bottom:.75rem;
+ color:#888;
+ text-align:left;
+ caption-side:bottom
+}
+th {
+ text-align:inherit
+}
+label {
+ display:inline-block;
+ margin-bottom:.5rem
+}
+button {
+ border-radius:0
+}
+button:focus {
+ outline:1px dotted;
+ outline:5px auto -webkit-focus-ring-color
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ margin:0;
+ font-family:inherit;
+ font-size:inherit;
+ line-height:inherit
+}
+button,
+input {
+ overflow:visible
+}
+button,
+select {
+ text-transform:none
+}
+[role=button] {
+ cursor:pointer
+}
+select {
+ word-wrap:normal
+}
+[type=button],
+[type=reset],
+[type=submit],
+button {
+ -webkit-appearance:button
+}
+[type=button]:not(:disabled),
+[type=reset]:not(:disabled),
+[type=submit]:not(:disabled),
+button:not(:disabled) {
+ cursor:pointer
+}
+[type=button]::-moz-focus-inner,
+[type=reset]::-moz-focus-inner,
+[type=submit]::-moz-focus-inner,
+button::-moz-focus-inner {
+ padding:0;
+ border-style:none
+}
+input[type=checkbox],
+input[type=radio] {
+ box-sizing:border-box;
+ padding:0
+}
+textarea {
+ overflow:auto;
+ resize:vertical
+}
+fieldset {
+ min-width:0;
+ padding:0;
+ margin:0;
+ border:0
+}
+legend {
+ display:block;
+ width:100%;
+ max-width:100%;
+ padding:0;
+ margin-bottom:.5rem;
+ font-size:1.5rem;
+ line-height:inherit;
+ color:inherit;
+ white-space:normal
+}
+progress {
+ vertical-align:baseline
+}
+[type=number]::-webkit-inner-spin-button,
+[type=number]::-webkit-outer-spin-button {
+ height:auto
+}
+[type=search] {
+ outline-offset:-2px;
+ -webkit-appearance:none
+}
+[type=search]::-webkit-search-decoration {
+ -webkit-appearance:none
+}
+::-webkit-file-upload-button {
+ font:inherit;
+ -webkit-appearance:button
+}
+output {
+ display:inline-block
+}
+summary {
+ display:list-item;
+ cursor:pointer
+}
+template {
+ display:none
+}
+[hidden] {
+ display:none!important
+}
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-bottom:.5rem;
+ font-weight:500;
+ line-height:1.2
+}
+.h1,
+h1 {
+ font-size:3rem
+}
+.h2,
+h2 {
+ font-size:2.5rem
+}
+.h3,
+h3 {
+ font-size:2rem
+}
+.h4,
+h4 {
+ font-size:1.40625rem
+}
+.h5,
+h5 {
+ font-size:1.17188rem
+}
+.h6,
+h6 {
+ font-size:.9375rem
+}
+.lead {
+ font-size:1.17188rem;
+ font-weight:300
+}
+.display-1 {
+ font-size:6rem;
+ font-weight:300;
+ line-height:1.2
+}
+.display-2 {
+ font-size:5.5rem;
+ font-weight:300;
+ line-height:1.2
+}
+.display-3 {
+ font-size:4.5rem;
+ font-weight:300;
+ line-height:1.2
+}
+.display-4 {
+ font-size:3.5rem;
+ font-weight:300;
+ line-height:1.2
+}
+hr {
+ margin-top:1rem;
+ margin-bottom:1rem;
+ border:0;
+ border-top:1px solid rgba(0,0,0,.1)
+}
+.small,
+small {
+ font-size:80%;
+ font-weight:400
+}
+.mark,
+mark {
+ padding:.2em;
+ background-color:#333
+}
+.list-unstyled {
+ padding-left:0;
+ list-style:none
+}
+.list-inline {
+ padding-left:0;
+ list-style:none
+}
+.list-inline-item {
+ display:inline-block
+}
+.list-inline-item:not(:last-child) {
+ margin-right:.5rem
+}
+.initialism {
+ font-size:90%;
+ text-transform:uppercase
+}
+.blockquote {
+ margin-bottom:1rem;
+ font-size:1.17188rem
+}
+.blockquote-footer {
+ display:block;
+ font-size:80%;
+ color:#888
+}
+.blockquote-footer::before {
+ content:"\2014\00A0"
+}
+.img-fluid {
+ max-width:100%;
+ height:auto
+}
+.img-thumbnail {
+ padding:.25rem;
+ background-color:#222;
+ border:1px solid #dee2e6;
+ border-radius:.25rem;
+ max-width:100%;
+ height:auto
+}
+.figure {
+ display:inline-block
+}
+.figure-img {
+ margin-bottom:.5rem;
+ line-height:1
+}
+.figure-caption {
+ font-size:90%;
+ color:#888
+}
+code {
+ font-size:87.5%;
+ color:#e83e8c;
+ word-wrap:break-word
+}
+a>code {
+ color:inherit
+}
+kbd {
+ padding:.2rem .4rem;
+ font-size:87.5%;
+ color:#fff;
+ background-color:#222;
+ border-radius:.2rem
+}
+kbd kbd {
+ padding:0;
+ font-size:100%;
+ font-weight:700
+}
+pre {
+ display:block;
+ font-size:87.5%;
+ color:inherit
+}
+pre code {
+ font-size:inherit;
+ color:inherit;
+ word-break:normal
+}
+.pre-scrollable {
+ max-height:340px;
+ overflow-y:scroll
+}
+.container {
+ width:100%;
+ padding-right:15px;
+ padding-left:15px;
+ margin-right:auto;
+ margin-left:auto
+}
+@media (min-width:576px) {
+ .container {
+  max-width:540px
+ }
+}
+@media (min-width:768px) {
+ .container {
+  max-width:720px
+ }
+}
+@media (min-width:992px) {
+ .container {
+  max-width:960px
+ }
+}
+@media (min-width:1200px) {
+ .container {
+  max-width:1140px
+ }
+}
+.container-fluid,
+.container-lg,
+.container-md,
+.container-sm,
+.container-xl {
+ width:100%;
+ padding-right:15px;
+ padding-left:15px;
+ margin-right:auto;
+ margin-left:auto
+}
+@media (min-width:576px) {
+ .container,
+ .container-sm {
+  max-width:540px
+ }
+}
+@media (min-width:768px) {
+ .container,
+ .container-md,
+ .container-sm {
+  max-width:720px
+ }
+}
+@media (min-width:992px) {
+ .container,
+ .container-lg,
+ .container-md,
+ .container-sm {
+  max-width:960px
+ }
+}
+@media (min-width:1200px) {
+ .container,
+ .container-lg,
+ .container-md,
+ .container-sm,
+ .container-xl {
+  max-width:1140px
+ }
+}
+.row {
+ display:flex;
+ flex-wrap:wrap;
+ margin-right:-15px;
+ margin-left:-15px
+}
+.no-gutters {
+ margin-right:0;
+ margin-left:0
+}
+.no-gutters>.col,
+.no-gutters>[class*=col-] {
+ padding-right:0;
+ padding-left:0
+}
+.col,
+.col-1,
+.col-10,
+.col-11,
+.col-12,
+.col-2,
+.col-3,
+.col-4,
+.col-5,
+.col-6,
+.col-7,
+.col-8,
+.col-9,
+.col-auto,
+.col-lg,
+.col-lg-1,
+.col-lg-10,
+.col-lg-11,
+.col-lg-12,
+.col-lg-2,
+.col-lg-3,
+.col-lg-4,
+.col-lg-5,
+.col-lg-6,
+.col-lg-7,
+.col-lg-8,
+.col-lg-9,
+.col-lg-auto,
+.col-md,
+.col-md-1,
+.col-md-10,
+.col-md-11,
+.col-md-12,
+.col-md-2,
+.col-md-3,
+.col-md-4,
+.col-md-5,
+.col-md-6,
+.col-md-7,
+.col-md-8,
+.col-md-9,
+.col-md-auto,
+.col-sm,
+.col-sm-1,
+.col-sm-10,
+.col-sm-11,
+.col-sm-12,
+.col-sm-2,
+.col-sm-3,
+.col-sm-4,
+.col-sm-5,
+.col-sm-6,
+.col-sm-7,
+.col-sm-8,
+.col-sm-9,
+.col-sm-auto,
+.col-xl,
+.col-xl-1,
+.col-xl-10,
+.col-xl-11,
+.col-xl-12,
+.col-xl-2,
+.col-xl-3,
+.col-xl-4,
+.col-xl-5,
+.col-xl-6,
+.col-xl-7,
+.col-xl-8,
+.col-xl-9,
+.col-xl-auto {
+ position:relative;
+ width:100%;
+ padding-right:15px;
+ padding-left:15px
+}
+.col {
+ flex-basis:0;
+ flex-grow:1;
+ min-width:0;
+ max-width:100%
+}
+.row-cols-1>* {
+ flex:0 0 100%;
+ max-width:100%
+}
+.row-cols-2>* {
+ flex:0 0 50%;
+ max-width:50%
+}
+.row-cols-3>* {
+ flex:0 0 33.33333%;
+ max-width:33.33333%
+}
+.row-cols-4>* {
+ flex:0 0 25%;
+ max-width:25%
+}
+.row-cols-5>* {
+ flex:0 0 20%;
+ max-width:20%
+}
+.row-cols-6>* {
+ flex:0 0 16.66667%;
+ max-width:16.66667%
+}
+.col-auto {
+ flex:0 0 auto;
+ width:auto;
+ max-width:100%
+}
+.col-1 {
+ flex:0 0 8.33333%;
+ max-width:8.33333%
+}
+.col-2 {
+ flex:0 0 16.66667%;
+ max-width:16.66667%
+}
+.col-3 {
+ flex:0 0 25%;
+ max-width:25%
+}
+.col-4 {
+ flex:0 0 33.33333%;
+ max-width:33.33333%
+}
+.col-5 {
+ flex:0 0 41.66667%;
+ max-width:41.66667%
+}
+.col-6 {
+ flex:0 0 50%;
+ max-width:50%
+}
+.col-7 {
+ flex:0 0 58.33333%;
+ max-width:58.33333%
+}
+.col-8 {
+ flex:0 0 66.66667%;
+ max-width:66.66667%
+}
+.col-9 {
+ flex:0 0 75%;
+ max-width:75%
+}
+.col-10 {
+ flex:0 0 83.33333%;
+ max-width:83.33333%
+}
+.col-11 {
+ flex:0 0 91.66667%;
+ max-width:91.66667%
+}
+.col-12 {
+ flex:0 0 100%;
+ max-width:100%
+}
+.order-first {
+ order:-1
+}
+.order-last {
+ order:13
+}
+.order-0 {
+ order:0
+}
+.order-1 {
+ order:1
+}
+.order-2 {
+ order:2
+}
+.order-3 {
+ order:3
+}
+.order-4 {
+ order:4
+}
+.order-5 {
+ order:5
+}
+.order-6 {
+ order:6
+}
+.order-7 {
+ order:7
+}
+.order-8 {
+ order:8
+}
+.order-9 {
+ order:9
+}
+.order-10 {
+ order:10
+}
+.order-11 {
+ order:11
+}
+.order-12 {
+ order:12
+}
+.offset-1 {
+ margin-left:8.33333%
+}
+.offset-2 {
+ margin-left:16.66667%
+}
+.offset-3 {
+ margin-left:25%
+}
+.offset-4 {
+ margin-left:33.33333%
+}
+.offset-5 {
+ margin-left:41.66667%
+}
+.offset-6 {
+ margin-left:50%
+}
+.offset-7 {
+ margin-left:58.33333%
+}
+.offset-8 {
+ margin-left:66.66667%
+}
+.offset-9 {
+ margin-left:75%
+}
+.offset-10 {
+ margin-left:83.33333%
+}
+.offset-11 {
+ margin-left:91.66667%
+}
+@media (min-width:576px) {
+ .col-sm {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-sm-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-sm-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-sm-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-sm-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-sm-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-sm-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-sm-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-sm-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-sm-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-sm-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-sm-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-sm-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-sm-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-sm-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-sm-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-sm-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-sm-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-sm-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-sm-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-sm-first {
+  order:-1
+ }
+ .order-sm-last {
+  order:13
+ }
+ .order-sm-0 {
+  order:0
+ }
+ .order-sm-1 {
+  order:1
+ }
+ .order-sm-2 {
+  order:2
+ }
+ .order-sm-3 {
+  order:3
+ }
+ .order-sm-4 {
+  order:4
+ }
+ .order-sm-5 {
+  order:5
+ }
+ .order-sm-6 {
+  order:6
+ }
+ .order-sm-7 {
+  order:7
+ }
+ .order-sm-8 {
+  order:8
+ }
+ .order-sm-9 {
+  order:9
+ }
+ .order-sm-10 {
+  order:10
+ }
+ .order-sm-11 {
+  order:11
+ }
+ .order-sm-12 {
+  order:12
+ }
+ .offset-sm-0 {
+  margin-left:0
+ }
+ .offset-sm-1 {
+  margin-left:8.33333%
+ }
+ .offset-sm-2 {
+  margin-left:16.66667%
+ }
+ .offset-sm-3 {
+  margin-left:25%
+ }
+ .offset-sm-4 {
+  margin-left:33.33333%
+ }
+ .offset-sm-5 {
+  margin-left:41.66667%
+ }
+ .offset-sm-6 {
+  margin-left:50%
+ }
+ .offset-sm-7 {
+  margin-left:58.33333%
+ }
+ .offset-sm-8 {
+  margin-left:66.66667%
+ }
+ .offset-sm-9 {
+  margin-left:75%
+ }
+ .offset-sm-10 {
+  margin-left:83.33333%
+ }
+ .offset-sm-11 {
+  margin-left:91.66667%
+ }
+}
+@media (min-width:768px) {
+ .col-md {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-md-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-md-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-md-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-md-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-md-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-md-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-md-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-md-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-md-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-md-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-md-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-md-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-md-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-md-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-md-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-md-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-md-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-md-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-md-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-md-first {
+  order:-1
+ }
+ .order-md-last {
+  order:13
+ }
+ .order-md-0 {
+  order:0
+ }
+ .order-md-1 {
+  order:1
+ }
+ .order-md-2 {
+  order:2
+ }
+ .order-md-3 {
+  order:3
+ }
+ .order-md-4 {
+  order:4
+ }
+ .order-md-5 {
+  order:5
+ }
+ .order-md-6 {
+  order:6
+ }
+ .order-md-7 {
+  order:7
+ }
+ .order-md-8 {
+  order:8
+ }
+ .order-md-9 {
+  order:9
+ }
+ .order-md-10 {
+  order:10
+ }
+ .order-md-11 {
+  order:11
+ }
+ .order-md-12 {
+  order:12
+ }
+ .offset-md-0 {
+  margin-left:0
+ }
+ .offset-md-1 {
+  margin-left:8.33333%
+ }
+ .offset-md-2 {
+  margin-left:16.66667%
+ }
+ .offset-md-3 {
+  margin-left:25%
+ }
+ .offset-md-4 {
+  margin-left:33.33333%
+ }
+ .offset-md-5 {
+  margin-left:41.66667%
+ }
+ .offset-md-6 {
+  margin-left:50%
+ }
+ .offset-md-7 {
+  margin-left:58.33333%
+ }
+ .offset-md-8 {
+  margin-left:66.66667%
+ }
+ .offset-md-9 {
+  margin-left:75%
+ }
+ .offset-md-10 {
+  margin-left:83.33333%
+ }
+ .offset-md-11 {
+  margin-left:91.66667%
+ }
+}
+@media (min-width:992px) {
+ .col-lg {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-lg-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-lg-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-lg-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-lg-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-lg-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-lg-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-lg-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-lg-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-lg-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-lg-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-lg-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-lg-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-lg-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-lg-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-lg-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-lg-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-lg-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-lg-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-lg-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-lg-first {
+  order:-1
+ }
+ .order-lg-last {
+  order:13
+ }
+ .order-lg-0 {
+  order:0
+ }
+ .order-lg-1 {
+  order:1
+ }
+ .order-lg-2 {
+  order:2
+ }
+ .order-lg-3 {
+  order:3
+ }
+ .order-lg-4 {
+  order:4
+ }
+ .order-lg-5 {
+  order:5
+ }
+ .order-lg-6 {
+  order:6
+ }
+ .order-lg-7 {
+  order:7
+ }
+ .order-lg-8 {
+  order:8
+ }
+ .order-lg-9 {
+  order:9
+ }
+ .order-lg-10 {
+  order:10
+ }
+ .order-lg-11 {
+  order:11
+ }
+ .order-lg-12 {
+  order:12
+ }
+ .offset-lg-0 {
+  margin-left:0
+ }
+ .offset-lg-1 {
+  margin-left:8.33333%
+ }
+ .offset-lg-2 {
+  margin-left:16.66667%
+ }
+ .offset-lg-3 {
+  margin-left:25%
+ }
+ .offset-lg-4 {
+  margin-left:33.33333%
+ }
+ .offset-lg-5 {
+  margin-left:41.66667%
+ }
+ .offset-lg-6 {
+  margin-left:50%
+ }
+ .offset-lg-7 {
+  margin-left:58.33333%
+ }
+ .offset-lg-8 {
+  margin-left:66.66667%
+ }
+ .offset-lg-9 {
+  margin-left:75%
+ }
+ .offset-lg-10 {
+  margin-left:83.33333%
+ }
+ .offset-lg-11 {
+  margin-left:91.66667%
+ }
+}
+@media (min-width:1200px) {
+ .col-xl {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-xl-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-xl-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-xl-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-xl-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-xl-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-xl-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-xl-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-xl-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-xl-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-xl-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-xl-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-xl-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-xl-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-xl-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-xl-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-xl-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-xl-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-xl-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-xl-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-xl-first {
+  order:-1
+ }
+ .order-xl-last {
+  order:13
+ }
+ .order-xl-0 {
+  order:0
+ }
+ .order-xl-1 {
+  order:1
+ }
+ .order-xl-2 {
+  order:2
+ }
+ .order-xl-3 {
+  order:3
+ }
+ .order-xl-4 {
+  order:4
+ }
+ .order-xl-5 {
+  order:5
+ }
+ .order-xl-6 {
+  order:6
+ }
+ .order-xl-7 {
+  order:7
+ }
+ .order-xl-8 {
+  order:8
+ }
+ .order-xl-9 {
+  order:9
+ }
+ .order-xl-10 {
+  order:10
+ }
+ .order-xl-11 {
+  order:11
+ }
+ .order-xl-12 {
+  order:12
+ }
+ .offset-xl-0 {
+  margin-left:0
+ }
+ .offset-xl-1 {
+  margin-left:8.33333%
+ }
+ .offset-xl-2 {
+  margin-left:16.66667%
+ }
+ .offset-xl-3 {
+  margin-left:25%
+ }
+ .offset-xl-4 {
+  margin-left:33.33333%
+ }
+ .offset-xl-5 {
+  margin-left:41.66667%
+ }
+ .offset-xl-6 {
+  margin-left:50%
+ }
+ .offset-xl-7 {
+  margin-left:58.33333%
+ }
+ .offset-xl-8 {
+  margin-left:66.66667%
+ }
+ .offset-xl-9 {
+  margin-left:75%
+ }
+ .offset-xl-10 {
+  margin-left:83.33333%
+ }
+ .offset-xl-11 {
+  margin-left:91.66667%
+ }
+}
+.table {
+ width:100%;
+ margin-bottom:1rem;
+ color:#dee2e6
+}
+.table td,
+.table th {
+ padding:.75rem;
+ vertical-align:top;
+ border-top:1px solid #444
+}
+.table thead th {
+ vertical-align:bottom;
+ border-bottom:2px solid #444
+}
+.table tbody+tbody {
+ border-top:2px solid #444
+}
+.table-sm td,
+.table-sm th {
+ padding:.3rem
+}
+.table-bordered {
+ border:1px solid #444
+}
+.table-bordered td,
+.table-bordered th {
+ border:1px solid #444
+}
+.table-bordered thead td,
+.table-bordered thead th {
+ border-bottom-width:2px
+}
+.table-borderless tbody+tbody,
+.table-borderless td,
+.table-borderless th,
+.table-borderless thead th {
+ border:0
+}
+.table-striped tbody tr:nth-of-type(odd) {
+ background-color:#303030
+}
+.table-hover tbody tr:hover {
+ color:#dee2e6;
+ background-color:rgba(0,0,0,.075)
+}
+.table-primary,
+.table-primary>td,
+.table-primary>th {
+ background-color:#c7d1db
+}
+.table-primary tbody+tbody,
+.table-primary td,
+.table-primary th,
+.table-primary thead th {
+ border-color:#97a9bc
+}
+.table-hover .table-primary:hover {
+ background-color:#b7c4d1
+}
+.table-hover .table-primary:hover>td,
+.table-hover .table-primary:hover>th {
+ background-color:#b7c4d1
+}
+.table-secondary,
+.table-secondary>td,
+.table-secondary>th {
+ background-color:#cbcbcb
+}
+.table-secondary tbody+tbody,
+.table-secondary td,
+.table-secondary th,
+.table-secondary thead th {
+ border-color:#9e9e9e
+}
+.table-hover .table-secondary:hover {
+ background-color:#bebebe
+}
+.table-hover .table-secondary:hover>td,
+.table-hover .table-secondary:hover>th {
+ background-color:#bebebe
+}
+.table-success,
+.table-success>td,
+.table-success>th {
+ background-color:#b8ecdf
+}
+.table-success tbody+tbody,
+.table-success td,
+.table-success th,
+.table-success thead th {
+ border-color:#7adcc3
+}
+.table-hover .table-success:hover {
+ background-color:#a4e7d6
+}
+.table-hover .table-success:hover>td,
+.table-hover .table-success:hover>th {
+ background-color:#a4e7d6
+}
+.table-info,
+.table-info>td,
+.table-info>th {
+ background-color:#c6e2f5
+}
+.table-info tbody+tbody,
+.table-info td,
+.table-info th,
+.table-info thead th {
+ border-color:#95c9ec
+}
+.table-hover .table-info:hover {
+ background-color:#b0d7f1
+}
+.table-hover .table-info:hover>td,
+.table-hover .table-info:hover>th {
+ background-color:#b0d7f1
+}
+.table-warning,
+.table-warning>td,
+.table-warning>th {
+ background-color:#fce3bd
+}
+.table-warning tbody+tbody,
+.table-warning td,
+.table-warning th,
+.table-warning thead th {
+ border-color:#f9cc84
+}
+.table-hover .table-warning:hover {
+ background-color:#fbd9a5
+}
+.table-hover .table-warning:hover>td,
+.table-hover .table-warning:hover>th {
+ background-color:#fbd9a5
+}
+.table-danger,
+.table-danger>td,
+.table-danger>th {
+ background-color:#f8cdc8
+}
+.table-danger tbody+tbody,
+.table-danger td,
+.table-danger th,
+.table-danger thead th {
+ border-color:#f3a29a
+}
+.table-hover .table-danger:hover {
+ background-color:#f5b8b1
+}
+.table-hover .table-danger:hover>td,
+.table-hover .table-danger:hover>th {
+ background-color:#f5b8b1
+}
+.table-light,
+.table-light>td,
+.table-light>th {
+ background-color:#c5c5c5
+}
+.table-light tbody+tbody,
+.table-light td,
+.table-light th,
+.table-light thead th {
+ border-color:#939393
+}
+.table-hover .table-light:hover {
+ background-color:#b8b8b8
+}
+.table-hover .table-light:hover>td,
+.table-hover .table-light:hover>th {
+ background-color:#b8b8b8
+}
+.table-dark,
+.table-dark>td,
+.table-dark>th {
+ background-color:#f6f7f8
+}
+.table-dark tbody+tbody,
+.table-dark td,
+.table-dark th,
+.table-dark thead th {
+ border-color:#eef0f2
+}
+.table-hover .table-dark:hover {
+ background-color:#e8eaed
+}
+.table-hover .table-dark:hover>td,
+.table-hover .table-dark:hover>th {
+ background-color:#e8eaed
+}
+.table-active,
+.table-active>td,
+.table-active>th {
+ background-color:rgba(0,0,0,.075)
+}
+.table-hover .table-active:hover {
+ background-color:rgba(0,0,0,.075)
+}
+.table-hover .table-active:hover>td,
+.table-hover .table-active:hover>th {
+ background-color:rgba(0,0,0,.075)
+}
+.table .thead-dark th {
+ color:#fff;
+ background-color:#303030;
+ border-color:#434343
+}
+.table .thead-light th {
+ color:#444;
+ background-color:#ebebeb;
+ border-color:#444
+}
+.table-dark {
+ color:#fff;
+ background-color:#303030
+}
+.table-dark td,
+.table-dark th,
+.table-dark thead th {
+ border-color:#434343
+}
+.table-dark.table-bordered {
+ border:0
+}
+.table-dark.table-striped tbody tr:nth-of-type(odd) {
+ background-color:rgba(255,255,255,.05)
+}
+.table-dark.table-hover tbody tr:hover {
+ color:#fff;
+ background-color:rgba(255,255,255,.075)
+}
+@media (max-width:575.98px) {
+ .table-responsive-sm {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-sm>.table-bordered {
+  border:0
+ }
+}
+@media (max-width:767.98px) {
+ .table-responsive-md {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-md>.table-bordered {
+  border:0
+ }
+}
+@media (max-width:991.98px) {
+ .table-responsive-lg {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-lg>.table-bordered {
+  border:0
+ }
+}
+@media (max-width:1199.98px) {
+ .table-responsive-xl {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-xl>.table-bordered {
+  border:0
+ }
+}
+.table-responsive {
+ display:block;
+ width:100%;
+ overflow-x:auto;
+ -webkit-overflow-scrolling:touch
+}
+.table-responsive>.table-bordered {
+ border:0
+}
+.form-control {
+ display:block;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ padding:.375rem .75rem;
+ font-size:.9375rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#fff;
+ background-color:#444;
+ background-clip:padding-box;
+ border:1px solid #222;
+ border-radius:.25rem;
+ transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .form-control {
+  transition:none
+ }
+}
+.form-control::-ms-expand {
+ background-color:transparent;
+ border:0
+}
+.form-control:-moz-focusring {
+ color:transparent;
+ text-shadow:0 0 0 #fff
+}
+.form-control:focus {
+ color:#fff;
+ background-color:#444;
+ border-color:#c27373;
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.25)
+}
+.form-control::placeholder {
+ color:#888;
+ opacity:1
+}
+.form-control:disabled,
+.form-control[readonly] {
+ background-color:#2b2b2b;
+ opacity:1
+}
+input[type=date].form-control,
+input[type=datetime-local].form-control,
+input[type=month].form-control,
+input[type=time].form-control {
+ appearance:none
+}
+select.form-control:focus::-ms-value {
+ color:#fff;
+ background-color:#444
+}
+.form-control-file,
+.form-control-range {
+ display:block;
+ width:100%
+}
+.col-form-label {
+ padding-top:calc(.375rem + 1px);
+ padding-bottom:calc(.375rem + 1px);
+ margin-bottom:0;
+ font-size:inherit;
+ line-height:1.5
+}
+.col-form-label-lg {
+ padding-top:calc(.5rem + 1px);
+ padding-bottom:calc(.5rem + 1px);
+ font-size:1.17188rem;
+ line-height:1.5
+}
+.col-form-label-sm {
+ padding-top:calc(.25rem + 1px);
+ padding-bottom:calc(.25rem + 1px);
+ font-size:.82031rem;
+ line-height:1.5
+}
+.form-control-plaintext {
+ display:block;
+ width:100%;
+ padding:.375rem 0;
+ margin-bottom:0;
+ font-size:.9375rem;
+ line-height:1.5;
+ color:#dee2e6;
+ background-color:transparent;
+ border:solid transparent;
+ border-width:1px 0
+}
+.form-control-plaintext.form-control-lg,
+.form-control-plaintext.form-control-sm {
+ padding-right:0;
+ padding-left:0
+}
+.form-control-sm {
+ height:calc(1.5em + .5rem + 2px);
+ padding:.25rem .5rem;
+ font-size:.82031rem;
+ line-height:1.5;
+ border-radius:.2rem
+}
+.form-control-lg {
+ height:calc(1.5em + 1rem + 2px);
+ padding:.5rem 1rem;
+ font-size:1.17188rem;
+ line-height:1.5;
+ border-radius:.3rem
+}
+select.form-control[multiple],
+select.form-control[size] {
+ height:auto
+}
+textarea.form-control {
+ height:auto
+}
+.form-group {
+ margin-bottom:1rem
+}
+.form-text {
+ display:block;
+ margin-top:.25rem
+}
+.form-row {
+ display:flex;
+ flex-wrap:wrap;
+ margin-right:-5px;
+ margin-left:-5px
+}
+.form-row>.col,
+.form-row>[class*=col-] {
+ padding-right:5px;
+ padding-left:5px
+}
+.form-check {
+ position:relative;
+ display:block;
+ padding-left:1.25rem
+}
+.form-check-input {
+ position:absolute;
+ margin-top:.3rem;
+ margin-left:-1.25rem
+}
+.form-check-input:disabled~.form-check-label,
+.form-check-input[disabled]~.form-check-label {
+ color:#888
+}
+.form-check-label {
+ margin-bottom:0
+}
+.form-check-inline {
+ display:inline-flex;
+ align-items:center;
+ padding-left:0;
+ margin-right:.75rem
+}
+.form-check-inline .form-check-input {
+ position:static;
+ margin-top:0;
+ margin-right:.3125rem;
+ margin-left:0
+}
+.valid-feedback {
+ display:none;
+ width:100%;
+ margin-top:.25rem;
+ font-size:80%;
+ color:#00bc8c
+}
+.valid-tooltip {
+ position:absolute;
+ top:100%;
+ z-index:5;
+ display:none;
+ max-width:100%;
+ padding:.25rem .5rem;
+ margin-top:.1rem;
+ font-size:.82031rem;
+ line-height:1.5;
+ color:#fff;
+ background-color:rgba(0,188,140,.9);
+ border-radius:.25rem
+}
+.is-valid~.valid-feedback,
+.is-valid~.valid-tooltip,
+.was-validated :valid~.valid-feedback,
+.was-validated :valid~.valid-tooltip {
+ display:block
+}
+.form-control.is-valid,
+.was-validated .form-control:valid {
+ border-color:#00bc8c;
+ padding-right:calc(1.5em + .75rem);
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2300bc8c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
+ background-repeat:no-repeat;
+ background-position:right calc(.375em + .1875rem) center;
+ background-size:calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.form-control.is-valid:focus,
+.was-validated .form-control:valid:focus {
+ border-color:#00bc8c;
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.25)
+}
+.was-validated textarea.form-control:valid,
+textarea.form-control.is-valid {
+ padding-right:calc(1.5em + .75rem);
+ background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)
+}
+.custom-select.is-valid,
+.was-validated .custom-select:valid {
+ border-color:#00bc8c;
+ padding-right:calc(.75em + 2.3125rem);
+ background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2300bc8c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #444 no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.custom-select.is-valid:focus,
+.was-validated .custom-select:valid:focus {
+ border-color:#00bc8c;
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.25)
+}
+.form-check-input.is-valid~.form-check-label,
+.was-validated .form-check-input:valid~.form-check-label {
+ color:#00bc8c
+}
+.form-check-input.is-valid~.valid-feedback,
+.form-check-input.is-valid~.valid-tooltip,
+.was-validated .form-check-input:valid~.valid-feedback,
+.was-validated .form-check-input:valid~.valid-tooltip {
+ display:block
+}
+.custom-control-input.is-valid~.custom-control-label,
+.was-validated .custom-control-input:valid~.custom-control-label {
+ color:#00bc8c
+}
+.custom-control-input.is-valid~.custom-control-label::before,
+.was-validated .custom-control-input:valid~.custom-control-label::before {
+ border-color:#00bc8c
+}
+.custom-control-input.is-valid:checked~.custom-control-label::before,
+.was-validated .custom-control-input:valid:checked~.custom-control-label::before {
+ border-color:#00efb2;
+ background-color:#00efb2
+}
+.custom-control-input.is-valid:focus~.custom-control-label::before,
+.was-validated .custom-control-input:valid:focus~.custom-control-label::before {
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.25)
+}
+.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,
+.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before {
+ border-color:#00bc8c
+}
+.custom-file-input.is-valid~.custom-file-label,
+.was-validated .custom-file-input:valid~.custom-file-label {
+ border-color:#00bc8c
+}
+.custom-file-input.is-valid:focus~.custom-file-label,
+.was-validated .custom-file-input:valid:focus~.custom-file-label {
+ border-color:#00bc8c;
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.25)
+}
+.invalid-feedback {
+ display:none;
+ width:100%;
+ margin-top:.25rem;
+ font-size:80%;
+ color:#e74c3c
+}
+.invalid-tooltip {
+ position:absolute;
+ top:100%;
+ z-index:5;
+ display:none;
+ max-width:100%;
+ padding:.25rem .5rem;
+ margin-top:.1rem;
+ font-size:.82031rem;
+ line-height:1.5;
+ color:#fff;
+ background-color:rgba(231,76,60,.9);
+ border-radius:.25rem
+}
+.is-invalid~.invalid-feedback,
+.is-invalid~.invalid-tooltip,
+.was-validated :invalid~.invalid-feedback,
+.was-validated :invalid~.invalid-tooltip {
+ display:block
+}
+.form-control.is-invalid,
+.was-validated .form-control:invalid {
+ border-color:#e74c3c;
+ padding-right:calc(1.5em + .75rem);
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23e74c3c' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e74c3c' stroke='none'/%3e%3c/svg%3e");
+ background-repeat:no-repeat;
+ background-position:right calc(.375em + .1875rem) center;
+ background-size:calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.form-control.is-invalid:focus,
+.was-validated .form-control:invalid:focus {
+ border-color:#e74c3c;
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.25)
+}
+.was-validated textarea.form-control:invalid,
+textarea.form-control.is-invalid {
+ padding-right:calc(1.5em + .75rem);
+ background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)
+}
+.custom-select.is-invalid,
+.was-validated .custom-select:invalid {
+ border-color:#e74c3c;
+ padding-right:calc(.75em + 2.3125rem);
+ background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23e74c3c' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e74c3c' stroke='none'/%3e%3c/svg%3e") #444 no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.custom-select.is-invalid:focus,
+.was-validated .custom-select:invalid:focus {
+ border-color:#e74c3c;
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.25)
+}
+.form-check-input.is-invalid~.form-check-label,
+.was-validated .form-check-input:invalid~.form-check-label {
+ color:#e74c3c
+}
+.form-check-input.is-invalid~.invalid-feedback,
+.form-check-input.is-invalid~.invalid-tooltip,
+.was-validated .form-check-input:invalid~.invalid-feedback,
+.was-validated .form-check-input:invalid~.invalid-tooltip {
+ display:block
+}
+.custom-control-input.is-invalid~.custom-control-label,
+.was-validated .custom-control-input:invalid~.custom-control-label {
+ color:#e74c3c
+}
+.custom-control-input.is-invalid~.custom-control-label::before,
+.was-validated .custom-control-input:invalid~.custom-control-label::before {
+ border-color:#e74c3c
+}
+.custom-control-input.is-invalid:checked~.custom-control-label::before,
+.was-validated .custom-control-input:invalid:checked~.custom-control-label::before {
+ border-color:#ed7669;
+ background-color:#ed7669
+}
+.custom-control-input.is-invalid:focus~.custom-control-label::before,
+.was-validated .custom-control-input:invalid:focus~.custom-control-label::before {
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.25)
+}
+.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,
+.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before {
+ border-color:#e74c3c
+}
+.custom-file-input.is-invalid~.custom-file-label,
+.was-validated .custom-file-input:invalid~.custom-file-label {
+ border-color:#e74c3c
+}
+.custom-file-input.is-invalid:focus~.custom-file-label,
+.was-validated .custom-file-input:invalid:focus~.custom-file-label {
+ border-color:#e74c3c;
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.25)
+}
+.form-inline {
+ display:flex;
+ flex-flow:row wrap;
+ align-items:center
+}
+.form-inline .form-check {
+ width:100%
+}
+@media (min-width:576px) {
+ .form-inline label {
+  display:flex;
+  align-items:center;
+  justify-content:center;
+  margin-bottom:0
+ }
+ .form-inline .form-group {
+  display:flex;
+  flex:0 0 auto;
+  flex-flow:row wrap;
+  align-items:center;
+  margin-bottom:0
+ }
+ .form-inline .form-control {
+  display:inline-block;
+  width:auto;
+  vertical-align:middle
+ }
+ .form-inline .form-control-plaintext {
+  display:inline-block
+ }
+ .form-inline .custom-select,
+ .form-inline .input-group {
+  width:auto
+ }
+ .form-inline .form-check {
+  display:flex;
+  align-items:center;
+  justify-content:center;
+  width:auto;
+  padding-left:0
+ }
+ .form-inline .form-check-input {
+  position:relative;
+  flex-shrink:0;
+  margin-top:0;
+  margin-right:.25rem;
+  margin-left:0
+ }
+ .form-inline .custom-control {
+  align-items:center;
+  justify-content:center
+ }
+ .form-inline .custom-control-label {
+  margin-bottom:0
+ }
+}
+.btn {
+ display:inline-block;
+ font-weight:400;
+ color:#dee2e6;
+ text-align:center;
+ vertical-align:middle;
+ user-select:none;
+ background-color:transparent;
+ border:1px solid transparent;
+ padding:.375rem .75rem;
+ font-size:.9375rem;
+ line-height:1.5;
+ border-radius:.25rem;
+ transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .btn {
+  transition:none
+ }
+}
+.btn:hover {
+ color:#dee2e6;
+ text-decoration:none
+}
+.btn.focus,
+.btn:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.25)
+}
+.btn.disabled,
+.btn:disabled {
+ opacity:.65
+}
+.btn:not(:disabled):not(.disabled) {
+ cursor:pointer
+}
+a.btn.disabled,
+fieldset:disabled a.btn {
+ pointer-events:none
+}
+.btn-primary {
+ color:#fff;
+ background-color:#375a7f;
+ border-color:#375a7f
+}
+.btn-primary:hover {
+ color:#fff;
+ background-color:#2b4764;
+ border-color:#28415b
+}
+.btn-primary.focus,
+.btn-primary:focus {
+ color:#fff;
+ background-color:#2b4764;
+ border-color:#28415b;
+ box-shadow:0 0 0 .2rem rgba(85,115,146,.5)
+}
+.btn-primary.disabled,
+.btn-primary:disabled {
+ color:#fff;
+ background-color:#375a7f;
+ border-color:#375a7f
+}
+.btn-primary:not(:disabled):not(.disabled).active,
+.btn-primary:not(:disabled):not(.disabled):active,
+.show>.btn-primary.dropdown-toggle {
+ color:#fff;
+ background-color:#28415b;
+ border-color:#243a53
+}
+.btn-primary:not(:disabled):not(.disabled).active:focus,
+.btn-primary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-primary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(85,115,146,.5)
+}
+.btn-secondary {
+ color:#fff;
+ background-color:#444;
+ border-color:#444
+}
+.btn-secondary:hover {
+ color:#fff;
+ background-color:#313131;
+ border-color:#2b2b2b
+}
+.btn-secondary.focus,
+.btn-secondary:focus {
+ color:#fff;
+ background-color:#313131;
+ border-color:#2b2b2b;
+ box-shadow:0 0 0 .2rem rgba(96,96,96,.5)
+}
+.btn-secondary.disabled,
+.btn-secondary:disabled {
+ color:#fff;
+ background-color:#444;
+ border-color:#444
+}
+.btn-secondary:not(:disabled):not(.disabled).active,
+.btn-secondary:not(:disabled):not(.disabled):active,
+.show>.btn-secondary.dropdown-toggle {
+ color:#fff;
+ background-color:#2b2b2b;
+ border-color:#242424
+}
+.btn-secondary:not(:disabled):not(.disabled).active:focus,
+.btn-secondary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-secondary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(96,96,96,.5)
+}
+.btn-success {
+ color:#fff;
+ background-color:#00bc8c;
+ border-color:#00bc8c
+}
+.btn-success:hover {
+ color:#fff;
+ background-color:#009670;
+ border-color:#008966
+}
+.btn-success.focus,
+.btn-success:focus {
+ color:#fff;
+ background-color:#009670;
+ border-color:#008966;
+ box-shadow:0 0 0 .2rem rgba(38,198,157,.5)
+}
+.btn-success.disabled,
+.btn-success:disabled {
+ color:#fff;
+ background-color:#00bc8c;
+ border-color:#00bc8c
+}
+.btn-success:not(:disabled):not(.disabled).active,
+.btn-success:not(:disabled):not(.disabled):active,
+.show>.btn-success.dropdown-toggle {
+ color:#fff;
+ background-color:#008966;
+ border-color:#007c5d
+}
+.btn-success:not(:disabled):not(.disabled).active:focus,
+.btn-success:not(:disabled):not(.disabled):active:focus,
+.show>.btn-success.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(38,198,157,.5)
+}
+.btn-info {
+ color:#fff;
+ background-color:#3498db;
+ border-color:#3498db
+}
+.btn-info:hover {
+ color:#fff;
+ background-color:#2384c6;
+ border-color:#217dbb
+}
+.btn-info.focus,
+.btn-info:focus {
+ color:#fff;
+ background-color:#2384c6;
+ border-color:#217dbb;
+ box-shadow:0 0 0 .2rem rgba(82,167,224,.5)
+}
+.btn-info.disabled,
+.btn-info:disabled {
+ color:#fff;
+ background-color:#3498db;
+ border-color:#3498db
+}
+.btn-info:not(:disabled):not(.disabled).active,
+.btn-info:not(:disabled):not(.disabled):active,
+.show>.btn-info.dropdown-toggle {
+ color:#fff;
+ background-color:#217dbb;
+ border-color:#1f76b0
+}
+.btn-info:not(:disabled):not(.disabled).active:focus,
+.btn-info:not(:disabled):not(.disabled):active:focus,
+.show>.btn-info.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(82,167,224,.5)
+}
+.btn-warning {
+ color:#fff;
+ background-color:#f39c12;
+ border-color:#f39c12
+}
+.btn-warning:hover {
+ color:#fff;
+ background-color:#d4860b;
+ border-color:#c87f0a
+}
+.btn-warning.focus,
+.btn-warning:focus {
+ color:#fff;
+ background-color:#d4860b;
+ border-color:#c87f0a;
+ box-shadow:0 0 0 .2rem rgba(245,171,54,.5)
+}
+.btn-warning.disabled,
+.btn-warning:disabled {
+ color:#fff;
+ background-color:#f39c12;
+ border-color:#f39c12
+}
+.btn-warning:not(:disabled):not(.disabled).active,
+.btn-warning:not(:disabled):not(.disabled):active,
+.show>.btn-warning.dropdown-toggle {
+ color:#fff;
+ background-color:#c87f0a;
+ border-color:#bc770a
+}
+.btn-warning:not(:disabled):not(.disabled).active:focus,
+.btn-warning:not(:disabled):not(.disabled):active:focus,
+.show>.btn-warning.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(245,171,54,.5)
+}
+.btn-danger {
+ color:#fff;
+ background-color:#e74c3c;
+ border-color:#e74c3c
+}
+.btn-danger:hover {
+ color:#fff;
+ background-color:#e12e1c;
+ border-color:#d62c1a
+}
+.btn-danger.focus,
+.btn-danger:focus {
+ color:#fff;
+ background-color:#e12e1c;
+ border-color:#d62c1a;
+ box-shadow:0 0 0 .2rem rgba(235,103,89,.5)
+}
+.btn-danger.disabled,
+.btn-danger:disabled {
+ color:#fff;
+ background-color:#e74c3c;
+ border-color:#e74c3c
+}
+.btn-danger:not(:disabled):not(.disabled).active,
+.btn-danger:not(:disabled):not(.disabled):active,
+.show>.btn-danger.dropdown-toggle {
+ color:#fff;
+ background-color:#d62c1a;
+ border-color:#ca2a19
+}
+.btn-danger:not(:disabled):not(.disabled).active:focus,
+.btn-danger:not(:disabled):not(.disabled):active:focus,
+.show>.btn-danger.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(235,103,89,.5)
+}
+.btn-light {
+ color:#fff;
+ background-color:#303030;
+ border-color:#303030
+}
+.btn-light:hover {
+ color:#fff;
+ background-color:#1d1d1d;
+ border-color:#171717
+}
+.btn-light.focus,
+.btn-light:focus {
+ color:#fff;
+ background-color:#1d1d1d;
+ border-color:#171717;
+ box-shadow:0 0 0 .2rem rgba(79,79,79,.5)
+}
+.btn-light.disabled,
+.btn-light:disabled {
+ color:#fff;
+ background-color:#303030;
+ border-color:#303030
+}
+.btn-light:not(:disabled):not(.disabled).active,
+.btn-light:not(:disabled):not(.disabled):active,
+.show>.btn-light.dropdown-toggle {
+ color:#fff;
+ background-color:#171717;
+ border-color:#101010
+}
+.btn-light:not(:disabled):not(.disabled).active:focus,
+.btn-light:not(:disabled):not(.disabled):active:focus,
+.show>.btn-light.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(79,79,79,.5)
+}
+.btn-dark {
+ color:#222;
+ background-color:#dee2e6;
+ border-color:#dee2e6
+}
+.btn-dark:hover {
+ color:#222;
+ background-color:#c8cfd6;
+ border-color:#c1c9d0
+}
+.btn-dark.focus,
+.btn-dark:focus {
+ color:#222;
+ background-color:#c8cfd6;
+ border-color:#c1c9d0;
+ box-shadow:0 0 0 .2rem rgba(194,197,201,.5)
+}
+.btn-dark.disabled,
+.btn-dark:disabled {
+ color:#222;
+ background-color:#dee2e6;
+ border-color:#dee2e6
+}
+.btn-dark:not(:disabled):not(.disabled).active,
+.btn-dark:not(:disabled):not(.disabled):active,
+.show>.btn-dark.dropdown-toggle {
+ color:#222;
+ background-color:#c1c9d0;
+ border-color:#bac2cb
+}
+.btn-dark:not(:disabled):not(.disabled).active:focus,
+.btn-dark:not(:disabled):not(.disabled):active:focus,
+.show>.btn-dark.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(194,197,201,.5)
+}
+.btn-outline-primary {
+ color:#375a7f;
+ border-color:#375a7f
+}
+.btn-outline-primary:hover {
+ color:#fff;
+ background-color:#375a7f;
+ border-color:#375a7f
+}
+.btn-outline-primary.focus,
+.btn-outline-primary:focus {
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.5)
+}
+.btn-outline-primary.disabled,
+.btn-outline-primary:disabled {
+ color:#375a7f;
+ background-color:transparent
+}
+.btn-outline-primary:not(:disabled):not(.disabled).active,
+.btn-outline-primary:not(:disabled):not(.disabled):active,
+.show>.btn-outline-primary.dropdown-toggle {
+ color:#fff;
+ background-color:#375a7f;
+ border-color:#375a7f
+}
+.btn-outline-primary:not(:disabled):not(.disabled).active:focus,
+.btn-outline-primary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-primary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.5)
+}
+.btn-outline-secondary {
+ color:#444;
+ border-color:#444
+}
+.btn-outline-secondary:hover {
+ color:#fff;
+ background-color:#444;
+ border-color:#444
+}
+.btn-outline-secondary.focus,
+.btn-outline-secondary:focus {
+ box-shadow:0 0 0 .2rem rgba(68,68,68,.5)
+}
+.btn-outline-secondary.disabled,
+.btn-outline-secondary:disabled {
+ color:#444;
+ background-color:transparent
+}
+.btn-outline-secondary:not(:disabled):not(.disabled).active,
+.btn-outline-secondary:not(:disabled):not(.disabled):active,
+.show>.btn-outline-secondary.dropdown-toggle {
+ color:#fff;
+ background-color:#444;
+ border-color:#444
+}
+.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
+.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-secondary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(68,68,68,.5)
+}
+.btn-outline-success {
+ color:#00bc8c;
+ border-color:#00bc8c
+}
+.btn-outline-success:hover {
+ color:#fff;
+ background-color:#00bc8c;
+ border-color:#00bc8c
+}
+.btn-outline-success.focus,
+.btn-outline-success:focus {
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.5)
+}
+.btn-outline-success.disabled,
+.btn-outline-success:disabled {
+ color:#00bc8c;
+ background-color:transparent
+}
+.btn-outline-success:not(:disabled):not(.disabled).active,
+.btn-outline-success:not(:disabled):not(.disabled):active,
+.show>.btn-outline-success.dropdown-toggle {
+ color:#fff;
+ background-color:#00bc8c;
+ border-color:#00bc8c
+}
+.btn-outline-success:not(:disabled):not(.disabled).active:focus,
+.btn-outline-success:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-success.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.5)
+}
+.btn-outline-info {
+ color:#3498db;
+ border-color:#3498db
+}
+.btn-outline-info:hover {
+ color:#fff;
+ background-color:#3498db;
+ border-color:#3498db
+}
+.btn-outline-info.focus,
+.btn-outline-info:focus {
+ box-shadow:0 0 0 .2rem rgba(52,152,219,.5)
+}
+.btn-outline-info.disabled,
+.btn-outline-info:disabled {
+ color:#3498db;
+ background-color:transparent
+}
+.btn-outline-info:not(:disabled):not(.disabled).active,
+.btn-outline-info:not(:disabled):not(.disabled):active,
+.show>.btn-outline-info.dropdown-toggle {
+ color:#fff;
+ background-color:#3498db;
+ border-color:#3498db
+}
+.btn-outline-info:not(:disabled):not(.disabled).active:focus,
+.btn-outline-info:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-info.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(52,152,219,.5)
+}
+.btn-outline-warning {
+ color:#f39c12;
+ border-color:#f39c12
+}
+.btn-outline-warning:hover {
+ color:#fff;
+ background-color:#f39c12;
+ border-color:#f39c12
+}
+.btn-outline-warning.focus,
+.btn-outline-warning:focus {
+ box-shadow:0 0 0 .2rem rgba(243,156,18,.5)
+}
+.btn-outline-warning.disabled,
+.btn-outline-warning:disabled {
+ color:#f39c12;
+ background-color:transparent
+}
+.btn-outline-warning:not(:disabled):not(.disabled).active,
+.btn-outline-warning:not(:disabled):not(.disabled):active,
+.show>.btn-outline-warning.dropdown-toggle {
+ color:#fff;
+ background-color:#f39c12;
+ border-color:#f39c12
+}
+.btn-outline-warning:not(:disabled):not(.disabled).active:focus,
+.btn-outline-warning:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-warning.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(243,156,18,.5)
+}
+.btn-outline-danger {
+ color:#e74c3c;
+ border-color:#e74c3c
+}
+.btn-outline-danger:hover {
+ color:#fff;
+ background-color:#e74c3c;
+ border-color:#e74c3c
+}
+.btn-outline-danger.focus,
+.btn-outline-danger:focus {
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.5)
+}
+.btn-outline-danger.disabled,
+.btn-outline-danger:disabled {
+ color:#e74c3c;
+ background-color:transparent
+}
+.btn-outline-danger:not(:disabled):not(.disabled).active,
+.btn-outline-danger:not(:disabled):not(.disabled):active,
+.show>.btn-outline-danger.dropdown-toggle {
+ color:#fff;
+ background-color:#e74c3c;
+ border-color:#e74c3c
+}
+.btn-outline-danger:not(:disabled):not(.disabled).active:focus,
+.btn-outline-danger:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-danger.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.5)
+}
+.btn-outline-light {
+ color:#303030;
+ border-color:#303030
+}
+.btn-outline-light:hover {
+ color:#fff;
+ background-color:#303030;
+ border-color:#303030
+}
+.btn-outline-light.focus,
+.btn-outline-light:focus {
+ box-shadow:0 0 0 .2rem rgba(48,48,48,.5)
+}
+.btn-outline-light.disabled,
+.btn-outline-light:disabled {
+ color:#303030;
+ background-color:transparent
+}
+.btn-outline-light:not(:disabled):not(.disabled).active,
+.btn-outline-light:not(:disabled):not(.disabled):active,
+.show>.btn-outline-light.dropdown-toggle {
+ color:#fff;
+ background-color:#303030;
+ border-color:#303030
+}
+.btn-outline-light:not(:disabled):not(.disabled).active:focus,
+.btn-outline-light:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-light.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(48,48,48,.5)
+}
+.btn-outline-dark {
+ color:#dee2e6;
+ border-color:#dee2e6
+}
+.btn-outline-dark:hover {
+ color:#222;
+ background-color:#dee2e6;
+ border-color:#dee2e6
+}
+.btn-outline-dark.focus,
+.btn-outline-dark:focus {
+ box-shadow:0 0 0 .2rem rgba(222,226,230,.5)
+}
+.btn-outline-dark.disabled,
+.btn-outline-dark:disabled {
+ color:#dee2e6;
+ background-color:transparent
+}
+.btn-outline-dark:not(:disabled):not(.disabled).active,
+.btn-outline-dark:not(:disabled):not(.disabled):active,
+.show>.btn-outline-dark.dropdown-toggle {
+ color:#222;
+ background-color:#dee2e6;
+ border-color:#dee2e6
+}
+.btn-outline-dark:not(:disabled):not(.disabled).active:focus,
+.btn-outline-dark:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-dark.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(222,226,230,.5)
+}
+.btn-link {
+ font-weight:400;
+ color:#e74c3c;
+ text-decoration:none
+}
+.btn-link:hover {
+ color:#a62f22;
+ text-decoration:underline
+}
+.btn-link.focus,
+.btn-link:focus {
+ text-decoration:underline
+}
+.btn-link.disabled,
+.btn-link:disabled {
+ color:#888;
+ pointer-events:none
+}
+.btn-group-lg>.btn,
+.btn-lg {
+ padding:.5rem 1rem;
+ font-size:1.17188rem;
+ line-height:1.5;
+ border-radius:.3rem
+}
+.btn-group-sm>.btn,
+.btn-sm {
+ padding:.25rem .5rem;
+ font-size:.82031rem;
+ line-height:1.5;
+ border-radius:.2rem
+}
+.btn-block {
+ display:block;
+ width:100%
+}
+.btn-block+.btn-block {
+ margin-top:.5rem
+}
+input[type=button].btn-block,
+input[type=reset].btn-block,
+input[type=submit].btn-block {
+ width:100%
+}
+.fade {
+ transition:opacity .15s linear
+}
+@media (prefers-reduced-motion:reduce) {
+ .fade {
+  transition:none
+ }
+}
+.fade:not(.show) {
+ opacity:0
+}
+.collapse:not(.show) {
+ display:none
+}
+.collapsing {
+ position:relative;
+ height:0;
+ overflow:hidden;
+ transition:height .35s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .collapsing {
+  transition:none
+ }
+}
+.dropdown,
+.dropleft,
+.dropright,
+.dropup {
+ position:relative
+}
+.dropdown-toggle {
+ white-space:nowrap
+}
+.dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:.3em solid;
+ border-right:.3em solid transparent;
+ border-bottom:0;
+ border-left:.3em solid transparent
+}
+.dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropdown-menu {
+ position:absolute;
+ top:100%;
+ left:0;
+ z-index:1000;
+ display:none;
+ float:left;
+ min-width:10rem;
+ padding:.5rem 0;
+ margin:.125rem 0 0;
+ font-size:.9375rem;
+ color:#dee2e6;
+ text-align:left;
+ list-style:none;
+ background-color:#222;
+ background-clip:padding-box;
+ border:1px solid #444;
+ border-radius:.25rem
+}
+.dropdown-menu-left {
+ right:auto;
+ left:0
+}
+.dropdown-menu-right {
+ right:0;
+ left:auto
+}
+@media (min-width:576px) {
+ .dropdown-menu-sm-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-sm-right {
+  right:0;
+  left:auto
+ }
+}
+@media (min-width:768px) {
+ .dropdown-menu-md-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-md-right {
+  right:0;
+  left:auto
+ }
+}
+@media (min-width:992px) {
+ .dropdown-menu-lg-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-lg-right {
+  right:0;
+  left:auto
+ }
+}
+@media (min-width:1200px) {
+ .dropdown-menu-xl-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-xl-right {
+  right:0;
+  left:auto
+ }
+}
+.dropup .dropdown-menu {
+ top:auto;
+ bottom:100%;
+ margin-top:0;
+ margin-bottom:.125rem
+}
+.dropup .dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:0;
+ border-right:.3em solid transparent;
+ border-bottom:.3em solid;
+ border-left:.3em solid transparent
+}
+.dropup .dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropright .dropdown-menu {
+ top:0;
+ right:auto;
+ left:100%;
+ margin-top:0;
+ margin-left:.125rem
+}
+.dropright .dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:.3em solid transparent;
+ border-right:0;
+ border-bottom:.3em solid transparent;
+ border-left:.3em solid
+}
+.dropright .dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropright .dropdown-toggle::after {
+ vertical-align:0
+}
+.dropleft .dropdown-menu {
+ top:0;
+ right:100%;
+ left:auto;
+ margin-top:0;
+ margin-right:.125rem
+}
+.dropleft .dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:""
+}
+.dropleft .dropdown-toggle::after {
+ display:none
+}
+.dropleft .dropdown-toggle::before {
+ display:inline-block;
+ margin-right:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:.3em solid transparent;
+ border-right:.3em solid;
+ border-bottom:.3em solid transparent
+}
+.dropleft .dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropleft .dropdown-toggle::before {
+ vertical-align:0
+}
+.dropdown-menu[x-placement^=bottom],
+.dropdown-menu[x-placement^=left],
+.dropdown-menu[x-placement^=right],
+.dropdown-menu[x-placement^=top] {
+ right:auto;
+ bottom:auto
+}
+.dropdown-divider {
+ height:0;
+ margin:.5rem 0;
+ overflow:hidden;
+ border-top:1px solid #444
+}
+.dropdown-item {
+ display:block;
+ width:100%;
+ padding:.25rem 1.5rem;
+ clear:both;
+ font-weight:400;
+ color:#fff;
+ text-align:inherit;
+ white-space:nowrap;
+ background-color:transparent;
+ border:0
+}
+.dropdown-item:focus,
+.dropdown-item:hover {
+ color:#fff;
+ text-decoration:none;
+ background-color:#375a7f
+}
+.dropdown-item.active,
+.dropdown-item:active {
+ color:#fff;
+ text-decoration:none;
+ background-color:#375a7f
+}
+.dropdown-item.disabled,
+.dropdown-item:disabled {
+ color:#888;
+ pointer-events:none;
+ background-color:transparent
+}
+.dropdown-menu.show {
+ display:block
+}
+.dropdown-header {
+ display:block;
+ padding:.5rem 1.5rem;
+ margin-bottom:0;
+ font-size:.82031rem;
+ color:#888;
+ white-space:nowrap
+}
+.dropdown-item-text {
+ display:block;
+ padding:.25rem 1.5rem;
+ color:#fff
+}
+.btn-group,
+.btn-group-vertical {
+ position:relative;
+ display:inline-flex;
+ vertical-align:middle
+}
+.btn-group-vertical>.btn,
+.btn-group>.btn {
+ position:relative;
+ flex:1 1 auto
+}
+.btn-group-vertical>.btn:hover,
+.btn-group>.btn:hover {
+ z-index:1
+}
+.btn-group-vertical>.btn.active,
+.btn-group-vertical>.btn:active,
+.btn-group-vertical>.btn:focus,
+.btn-group>.btn.active,
+.btn-group>.btn:active,
+.btn-group>.btn:focus {
+ z-index:1
+}
+.btn-toolbar {
+ display:flex;
+ flex-wrap:wrap;
+ justify-content:flex-start
+}
+.btn-toolbar .input-group {
+ width:auto
+}
+.btn-group>.btn-group:not(:first-child),
+.btn-group>.btn:not(:first-child) {
+ margin-left:-1px
+}
+.btn-group>.btn-group:not(:last-child)>.btn,
+.btn-group>.btn:not(:last-child):not(.dropdown-toggle) {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.btn-group>.btn-group:not(:first-child)>.btn,
+.btn-group>.btn:not(:first-child) {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.dropdown-toggle-split {
+ padding-right:.5625rem;
+ padding-left:.5625rem
+}
+.dropdown-toggle-split::after,
+.dropright .dropdown-toggle-split::after,
+.dropup .dropdown-toggle-split::after {
+ margin-left:0
+}
+.dropleft .dropdown-toggle-split::before {
+ margin-right:0
+}
+.btn-group-sm>.btn+.dropdown-toggle-split,
+.btn-sm+.dropdown-toggle-split {
+ padding-right:.375rem;
+ padding-left:.375rem
+}
+.btn-group-lg>.btn+.dropdown-toggle-split,
+.btn-lg+.dropdown-toggle-split {
+ padding-right:.75rem;
+ padding-left:.75rem
+}
+.btn-group-vertical {
+ flex-direction:column;
+ align-items:flex-start;
+ justify-content:center
+}
+.btn-group-vertical>.btn,
+.btn-group-vertical>.btn-group {
+ width:100%
+}
+.btn-group-vertical>.btn-group:not(:first-child),
+.btn-group-vertical>.btn:not(:first-child) {
+ margin-top:-1px
+}
+.btn-group-vertical>.btn-group:not(:last-child)>.btn,
+.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle) {
+ border-bottom-right-radius:0;
+ border-bottom-left-radius:0
+}
+.btn-group-vertical>.btn-group:not(:first-child)>.btn,
+.btn-group-vertical>.btn:not(:first-child) {
+ border-top-left-radius:0;
+ border-top-right-radius:0
+}
+.btn-group-toggle>.btn,
+.btn-group-toggle>.btn-group>.btn {
+ margin-bottom:0
+}
+.btn-group-toggle>.btn input[type=checkbox],
+.btn-group-toggle>.btn input[type=radio],
+.btn-group-toggle>.btn-group>.btn input[type=checkbox],
+.btn-group-toggle>.btn-group>.btn input[type=radio] {
+ position:absolute;
+ clip:rect(0,0,0,0);
+ pointer-events:none
+}
+.input-group {
+ position:relative;
+ display:flex;
+ flex-wrap:wrap;
+ align-items:stretch;
+ width:100%
+}
+.input-group>.custom-file,
+.input-group>.custom-select,
+.input-group>.form-control,
+.input-group>.form-control-plaintext {
+ position:relative;
+ flex:1 1 auto;
+ width:1%;
+ min-width:0;
+ margin-bottom:0
+}
+.input-group>.custom-file+.custom-file,
+.input-group>.custom-file+.custom-select,
+.input-group>.custom-file+.form-control,
+.input-group>.custom-select+.custom-file,
+.input-group>.custom-select+.custom-select,
+.input-group>.custom-select+.form-control,
+.input-group>.form-control+.custom-file,
+.input-group>.form-control+.custom-select,
+.input-group>.form-control+.form-control,
+.input-group>.form-control-plaintext+.custom-file,
+.input-group>.form-control-plaintext+.custom-select,
+.input-group>.form-control-plaintext+.form-control {
+ margin-left:-1px
+}
+.input-group>.custom-file .custom-file-input:focus~.custom-file-label,
+.input-group>.custom-select:focus,
+.input-group>.form-control:focus {
+ z-index:3
+}
+.input-group>.custom-file .custom-file-input:focus {
+ z-index:4
+}
+.input-group>.custom-select:not(:last-child),
+.input-group>.form-control:not(:last-child) {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.input-group>.custom-select:not(:first-child),
+.input-group>.form-control:not(:first-child) {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.input-group>.custom-file {
+ display:flex;
+ align-items:center
+}
+.input-group>.custom-file:not(:last-child) .custom-file-label,
+.input-group>.custom-file:not(:last-child) .custom-file-label::after {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.input-group>.custom-file:not(:first-child) .custom-file-label {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.input-group-append,
+.input-group-prepend {
+ display:flex
+}
+.input-group-append .btn,
+.input-group-prepend .btn {
+ position:relative;
+ z-index:2
+}
+.input-group-append .btn:focus,
+.input-group-prepend .btn:focus {
+ z-index:3
+}
+.input-group-append .btn+.btn,
+.input-group-append .btn+.input-group-text,
+.input-group-append .input-group-text+.btn,
+.input-group-append .input-group-text+.input-group-text,
+.input-group-prepend .btn+.btn,
+.input-group-prepend .btn+.input-group-text,
+.input-group-prepend .input-group-text+.btn,
+.input-group-prepend .input-group-text+.input-group-text {
+ margin-left:-1px
+}
+.input-group-prepend {
+ margin-right:-1px
+}
+.input-group-append {
+ margin-left:-1px
+}
+.input-group-text {
+ display:flex;
+ align-items:center;
+ padding:.375rem .75rem;
+ margin-bottom:0;
+ font-size:.9375rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#adb5bd;
+ text-align:center;
+ white-space:nowrap;
+ background-color:#444;
+ border:1px solid #222;
+ border-radius:.25rem
+}
+.input-group-text input[type=checkbox],
+.input-group-text input[type=radio] {
+ margin-top:0
+}
+.input-group-lg>.custom-select,
+.input-group-lg>.form-control:not(textarea) {
+ height:calc(1.5em + 1rem + 2px)
+}
+.input-group-lg>.custom-select,
+.input-group-lg>.form-control,
+.input-group-lg>.input-group-append>.btn,
+.input-group-lg>.input-group-append>.input-group-text,
+.input-group-lg>.input-group-prepend>.btn,
+.input-group-lg>.input-group-prepend>.input-group-text {
+ padding:.5rem 1rem;
+ font-size:1.17188rem;
+ line-height:1.5;
+ border-radius:.3rem
+}
+.input-group-sm>.custom-select,
+.input-group-sm>.form-control:not(textarea) {
+ height:calc(1.5em + .5rem + 2px)
+}
+.input-group-sm>.custom-select,
+.input-group-sm>.form-control,
+.input-group-sm>.input-group-append>.btn,
+.input-group-sm>.input-group-append>.input-group-text,
+.input-group-sm>.input-group-prepend>.btn,
+.input-group-sm>.input-group-prepend>.input-group-text {
+ padding:.25rem .5rem;
+ font-size:.82031rem;
+ line-height:1.5;
+ border-radius:.2rem
+}
+.input-group-lg>.custom-select,
+.input-group-sm>.custom-select {
+ padding-right:1.75rem
+}
+.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),
+.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),
+.input-group>.input-group-append:not(:last-child)>.btn,
+.input-group>.input-group-append:not(:last-child)>.input-group-text,
+.input-group>.input-group-prepend>.btn,
+.input-group>.input-group-prepend>.input-group-text {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.input-group>.input-group-append>.btn,
+.input-group>.input-group-append>.input-group-text,
+.input-group>.input-group-prepend:first-child>.btn:not(:first-child),
+.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),
+.input-group>.input-group-prepend:not(:first-child)>.btn,
+.input-group>.input-group-prepend:not(:first-child)>.input-group-text {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.custom-control {
+ position:relative;
+ display:block;
+ min-height:1.40625rem;
+ padding-left:1.5rem
+}
+.custom-control-inline {
+ display:inline-flex;
+ margin-right:1rem
+}
+.custom-control-input {
+ position:absolute;
+ left:0;
+ z-index:-1;
+ width:1rem;
+ height:1.20312rem;
+ opacity:0
+}
+.custom-control-input:checked~.custom-control-label::before {
+ color:#fff;
+ border-color:#375a7f;
+ background-color:#375a7f
+}
+.custom-control-input:focus~.custom-control-label::before {
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.25)
+}
+.custom-control-input:focus:not(:checked)~.custom-control-label::before {
+ border-color:#739ac2
+}
+.custom-control-input:not(:disabled):active~.custom-control-label::before {
+ color:#fff;
+ background-color:#97b3d2;
+ border-color:#97b3d2
+}
+.custom-control-input:disabled~.custom-control-label,
+.custom-control-input[disabled]~.custom-control-label {
+ color:#888
+}
+.custom-control-input:disabled~.custom-control-label::before,
+.custom-control-input[disabled]~.custom-control-label::before {
+ background-color:#2b2b2b
+}
+.custom-control-label {
+ position:relative;
+ margin-bottom:0;
+ vertical-align:top
+}
+.custom-control-label::before {
+ position:absolute;
+ top:.20312rem;
+ left:-1.5rem;
+ display:block;
+ width:1rem;
+ height:1rem;
+ pointer-events:none;
+ content:"";
+ background-color:#444;
+ border:#adb5bd solid 1px
+}
+.custom-control-label::after {
+ position:absolute;
+ top:.20312rem;
+ left:-1.5rem;
+ display:block;
+ width:1rem;
+ height:1rem;
+ content:"";
+ background:no-repeat 50%/50% 50%
+}
+.custom-checkbox .custom-control-label::before {
+ border-radius:.25rem
+}
+.custom-checkbox .custom-control-input:checked~.custom-control-label::after {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")
+}
+.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before {
+ border-color:#375a7f;
+ background-color:#375a7f
+}
+.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")
+}
+.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before {
+ background-color:rgba(55,90,127,.5)
+}
+.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before {
+ background-color:rgba(55,90,127,.5)
+}
+.custom-radio .custom-control-label::before {
+ border-radius:50%
+}
+.custom-radio .custom-control-input:checked~.custom-control-label::after {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")
+}
+.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before {
+ background-color:rgba(55,90,127,.5)
+}
+.custom-switch {
+ padding-left:2.25rem
+}
+.custom-switch .custom-control-label::before {
+ left:-2.25rem;
+ width:1.75rem;
+ pointer-events:all;
+ border-radius:.5rem
+}
+.custom-switch .custom-control-label::after {
+ top:calc(.20312rem + 2px);
+ left:calc(-2.25rem + 2px);
+ width:calc(1rem - 4px);
+ height:calc(1rem - 4px);
+ background-color:#adb5bd;
+ border-radius:.5rem;
+ transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-switch .custom-control-label::after {
+  transition:none
+ }
+}
+.custom-switch .custom-control-input:checked~.custom-control-label::after {
+ background-color:#444;
+ transform:translateX(.75rem)
+}
+.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before {
+ background-color:rgba(55,90,127,.5)
+}
+.custom-select {
+ display:inline-block;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ padding:.375rem 1.75rem .375rem .75rem;
+ font-size:.9375rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#fff;
+ vertical-align:middle;
+ background:#444 url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;
+ border:1px solid #222;
+ border-radius:.25rem;
+ appearance:none
+}
+.custom-select:focus {
+ border-color:#739ac2;
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.25)
+}
+.custom-select:focus::-ms-value {
+ color:#fff;
+ background-color:#444
+}
+.custom-select[multiple],
+.custom-select[size]:not([size="1"]) {
+ height:auto;
+ padding-right:.75rem;
+ background-image:none
+}
+.custom-select:disabled {
+ color:#888;
+ background-color:#ebebeb
+}
+.custom-select::-ms-expand {
+ display:none
+}
+.custom-select:-moz-focusring {
+ color:transparent;
+ text-shadow:0 0 0 #fff
+}
+.custom-select-sm {
+ height:calc(1.5em + .5rem + 2px);
+ padding-top:.25rem;
+ padding-bottom:.25rem;
+ padding-left:.5rem;
+ font-size:.82031rem
+}
+.custom-select-lg {
+ height:calc(1.5em + 1rem + 2px);
+ padding-top:.5rem;
+ padding-bottom:.5rem;
+ padding-left:1rem;
+ font-size:1.17188rem
+}
+.custom-file {
+ position:relative;
+ display:inline-block;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ margin-bottom:0
+}
+.custom-file-input {
+ position:relative;
+ z-index:2;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ margin:0;
+ opacity:0
+}
+.custom-file-input:focus~.custom-file-label {
+ border-color:#739ac2;
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.25)
+}
+.custom-file-input:disabled~.custom-file-label,
+.custom-file-input[disabled]~.custom-file-label {
+ background-color:#2b2b2b
+}
+.custom-file-input:lang(en)~.custom-file-label::after {
+ content:"Browse"
+}
+.custom-file-input~.custom-file-label[data-browse]::after {
+ content:attr(data-browse)
+}
+.custom-file-label {
+ position:absolute;
+ top:0;
+ right:0;
+ left:0;
+ z-index:1;
+ height:calc(1.5em + .75rem + 2px);
+ padding:.375rem .75rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#adb5bd;
+ background-color:#444;
+ border:1px solid #222;
+ border-radius:.25rem
+}
+.custom-file-label::after {
+ position:absolute;
+ top:0;
+ right:0;
+ bottom:0;
+ z-index:3;
+ display:block;
+ height:calc(1.5em + .75rem);
+ padding:.375rem .75rem;
+ line-height:1.5;
+ color:#adb5bd;
+ content:"Browse";
+ background-color:#444;
+ border-left:inherit;
+ border-radius:0 .25rem .25rem 0
+}
+.custom-range {
+ width:100%;
+ height:1.4rem;
+ padding:0;
+ background-color:transparent;
+ appearance:none
+}
+.custom-range:focus {
+ outline:0
+}
+.custom-range:focus::-webkit-slider-thumb {
+ box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)
+}
+.custom-range:focus::-moz-range-thumb {
+ box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)
+}
+.custom-range:focus::-ms-thumb {
+ box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)
+}
+.custom-range::-moz-focus-outer {
+ border:0
+}
+.custom-range::-webkit-slider-thumb {
+ width:1rem;
+ height:1rem;
+ margin-top:-.25rem;
+ background-color:#375a7f;
+ border:0;
+ border-radius:1rem;
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
+ appearance:none
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-range::-webkit-slider-thumb {
+  transition:none
+ }
+}
+.custom-range::-webkit-slider-thumb:active {
+ background-color:#97b3d2
+}
+.custom-range::-webkit-slider-runnable-track {
+ width:100%;
+ height:.5rem;
+ color:transparent;
+ cursor:pointer;
+ background-color:#dee2e6;
+ border-color:transparent;
+ border-radius:1rem
+}
+.custom-range::-moz-range-thumb {
+ width:1rem;
+ height:1rem;
+ background-color:#375a7f;
+ border:0;
+ border-radius:1rem;
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
+ appearance:none
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-range::-moz-range-thumb {
+  transition:none
+ }
+}
+.custom-range::-moz-range-thumb:active {
+ background-color:#97b3d2
+}
+.custom-range::-moz-range-track {
+ width:100%;
+ height:.5rem;
+ color:transparent;
+ cursor:pointer;
+ background-color:#dee2e6;
+ border-color:transparent;
+ border-radius:1rem
+}
+.custom-range::-ms-thumb {
+ width:1rem;
+ height:1rem;
+ margin-top:0;
+ margin-right:.2rem;
+ margin-left:.2rem;
+ background-color:#375a7f;
+ border:0;
+ border-radius:1rem;
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
+ appearance:none
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-range::-ms-thumb {
+  transition:none
+ }
+}
+.custom-range::-ms-thumb:active {
+ background-color:#97b3d2
+}
+.custom-range::-ms-track {
+ width:100%;
+ height:.5rem;
+ color:transparent;
+ cursor:pointer;
+ background-color:transparent;
+ border-color:transparent;
+ border-width:.5rem
+}
+.custom-range::-ms-fill-lower {
+ background-color:#dee2e6;
+ border-radius:1rem
+}
+.custom-range::-ms-fill-upper {
+ margin-right:15px;
+ background-color:#dee2e6;
+ border-radius:1rem
+}
+.custom-range:disabled::-webkit-slider-thumb {
+ background-color:#adb5bd
+}
+.custom-range:disabled::-webkit-slider-runnable-track {
+ cursor:default
+}
+.custom-range:disabled::-moz-range-thumb {
+ background-color:#adb5bd
+}
+.custom-range:disabled::-moz-range-track {
+ cursor:default
+}
+.custom-range:disabled::-ms-thumb {
+ background-color:#adb5bd
+}
+.custom-control-label::before,
+.custom-file-label,
+.custom-select {
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-control-label::before,
+ .custom-file-label,
+ .custom-select {
+  transition:none
+ }
+}
+.nav {
+ display:flex;
+ flex-wrap:wrap;
+ padding-left:0;
+ margin-bottom:0;
+ list-style:none
+}
+.nav-link {
+ display:block;
+ padding:.5rem 2rem
+}
+.nav-link:focus,
+.nav-link:hover {
+ text-decoration:none
+}
+.nav-link.disabled {
+ color:#adb5bd;
+ pointer-events:none;
+ cursor:default
+}
+.nav-tabs {
+ border-bottom:1px solid #444
+}
+.nav-tabs .nav-item {
+ margin-bottom:-1px
+}
+.nav-tabs .nav-link {
+ border:1px solid transparent;
+ border-top-left-radius:.25rem;
+ border-top-right-radius:.25rem
+}
+.nav-tabs .nav-link:focus,
+.nav-tabs .nav-link:hover {
+ border-color:#444 #444 transparent
+}
+.nav-tabs .nav-link.disabled {
+ color:#adb5bd;
+ background-color:transparent;
+ border-color:transparent
+}
+.nav-tabs .nav-item.show .nav-link,
+.nav-tabs .nav-link.active {
+ color:#fff;
+ background-color:#222;
+ border-color:#444 #444 transparent
+}
+.nav-tabs .dropdown-menu {
+ margin-top:-1px;
+ border-top-left-radius:0;
+ border-top-right-radius:0
+}
+.nav-pills .nav-link {
+ border-radius:.25rem
+}
+.nav-pills .nav-link.active,
+.nav-pills .show>.nav-link {
+ color:#fff;
+ background-color:#375a7f
+}
+.nav-fill .nav-item {
+ flex:1 1 auto;
+ text-align:center
+}
+.nav-justified .nav-item {
+ flex-basis:0;
+ flex-grow:1;
+ text-align:center
+}
+.tab-content>.tab-pane {
+ display:none
+}
+.tab-content>.active {
+ display:block
+}
+.navbar {
+ position:relative;
+ display:flex;
+ flex-wrap:wrap;
+ align-items:center;
+ justify-content:space-between;
+ padding:1rem 1rem
+}
+.navbar .container,
+.navbar .container-fluid,
+.navbar .container-lg,
+.navbar .container-md,
+.navbar .container-sm,
+.navbar .container-xl {
+ display:flex;
+ flex-wrap:wrap;
+ align-items:center;
+ justify-content:space-between
+}
+.navbar-brand {
+ display:inline-block;
+ padding-top:.32422rem;
+ padding-bottom:.32422rem;
+ margin-right:1rem;
+ font-size:1.17188rem;
+ line-height:inherit;
+ white-space:nowrap
+}
+.navbar-brand:focus,
+.navbar-brand:hover {
+ text-decoration:none
+}
+.navbar-nav {
+ display:flex;
+ flex-direction:column;
+ padding-left:0;
+ margin-bottom:0;
+ list-style:none
+}
+.navbar-nav .nav-link {
+ padding-right:0;
+ padding-left:0
+}
+.navbar-nav .dropdown-menu {
+ position:static;
+ float:none
+}
+.navbar-text {
+ display:inline-block;
+ padding-top:.5rem;
+ padding-bottom:.5rem
+}
+.navbar-collapse {
+ flex-basis:100%;
+ flex-grow:1;
+ align-items:center
+}
+.navbar-toggler {
+ padding:.25rem .75rem;
+ font-size:1.17188rem;
+ line-height:1;
+ background-color:transparent;
+ border:1px solid transparent;
+ border-radius:.25rem
+}
+.navbar-toggler:focus,
+.navbar-toggler:hover {
+ text-decoration:none
+}
+.navbar-toggler-icon {
+ display:inline-block;
+ width:1.5em;
+ height:1.5em;
+ vertical-align:middle;
+ content:"";
+ background:no-repeat center center;
+ background-size:100% 100%
+}
+@media (max-width:575.98px) {
+ .navbar-expand-sm>.container,
+ .navbar-expand-sm>.container-fluid,
+ .navbar-expand-sm>.container-lg,
+ .navbar-expand-sm>.container-md,
+ .navbar-expand-sm>.container-sm,
+ .navbar-expand-sm>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:576px) {
+ .navbar-expand-sm {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-sm .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-sm .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-sm .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-sm>.container,
+ .navbar-expand-sm>.container-fluid,
+ .navbar-expand-sm>.container-lg,
+ .navbar-expand-sm>.container-md,
+ .navbar-expand-sm>.container-sm,
+ .navbar-expand-sm>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-sm .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-sm .navbar-toggler {
+  display:none
+ }
+}
+@media (max-width:767.98px) {
+ .navbar-expand-md>.container,
+ .navbar-expand-md>.container-fluid,
+ .navbar-expand-md>.container-lg,
+ .navbar-expand-md>.container-md,
+ .navbar-expand-md>.container-sm,
+ .navbar-expand-md>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:768px) {
+ .navbar-expand-md {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-md .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-md .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-md .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-md>.container,
+ .navbar-expand-md>.container-fluid,
+ .navbar-expand-md>.container-lg,
+ .navbar-expand-md>.container-md,
+ .navbar-expand-md>.container-sm,
+ .navbar-expand-md>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-md .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-md .navbar-toggler {
+  display:none
+ }
+}
+@media (max-width:991.98px) {
+ .navbar-expand-lg>.container,
+ .navbar-expand-lg>.container-fluid,
+ .navbar-expand-lg>.container-lg,
+ .navbar-expand-lg>.container-md,
+ .navbar-expand-lg>.container-sm,
+ .navbar-expand-lg>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:992px) {
+ .navbar-expand-lg {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-lg .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-lg .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-lg .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-lg>.container,
+ .navbar-expand-lg>.container-fluid,
+ .navbar-expand-lg>.container-lg,
+ .navbar-expand-lg>.container-md,
+ .navbar-expand-lg>.container-sm,
+ .navbar-expand-lg>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-lg .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-lg .navbar-toggler {
+  display:none
+ }
+}
+@media (max-width:1199.98px) {
+ .navbar-expand-xl>.container,
+ .navbar-expand-xl>.container-fluid,
+ .navbar-expand-xl>.container-lg,
+ .navbar-expand-xl>.container-md,
+ .navbar-expand-xl>.container-sm,
+ .navbar-expand-xl>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:1200px) {
+ .navbar-expand-xl {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-xl .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-xl .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-xl .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-xl>.container,
+ .navbar-expand-xl>.container-fluid,
+ .navbar-expand-xl>.container-lg,
+ .navbar-expand-xl>.container-md,
+ .navbar-expand-xl>.container-sm,
+ .navbar-expand-xl>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-xl .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-xl .navbar-toggler {
+  display:none
+ }
+}
+.navbar-expand {
+ flex-flow:row nowrap;
+ justify-content:flex-start
+}
+.navbar-expand>.container,
+.navbar-expand>.container-fluid,
+.navbar-expand>.container-lg,
+.navbar-expand>.container-md,
+.navbar-expand>.container-sm,
+.navbar-expand>.container-xl {
+ padding-right:0;
+ padding-left:0
+}
+.navbar-expand .navbar-nav {
+ flex-direction:row
+}
+.navbar-expand .navbar-nav .dropdown-menu {
+ position:absolute
+}
+.navbar-expand .navbar-nav .nav-link {
+ padding-right:.5rem;
+ padding-left:.5rem
+}
+.navbar-expand>.container,
+.navbar-expand>.container-fluid,
+.navbar-expand>.container-lg,
+.navbar-expand>.container-md,
+.navbar-expand>.container-sm,
+.navbar-expand>.container-xl {
+ flex-wrap:nowrap
+}
+.navbar-expand .navbar-collapse {
+ display:flex!important;
+ flex-basis:auto
+}
+.navbar-expand .navbar-toggler {
+ display:none
+}
+.navbar-light .navbar-brand {
+ color:#fff
+}
+.navbar-light .navbar-brand:focus,
+.navbar-light .navbar-brand:hover {
+ color:#fff
+}
+.navbar-light .navbar-nav .nav-link {
+ color:rgba(255,255,255,.6)
+}
+.navbar-light .navbar-nav .nav-link:focus,
+.navbar-light .navbar-nav .nav-link:hover {
+ color:#fff
+}
+.navbar-light .navbar-nav .nav-link.disabled {
+ color:rgba(0,0,0,.3)
+}
+.navbar-light .navbar-nav .active>.nav-link,
+.navbar-light .navbar-nav .nav-link.active,
+.navbar-light .navbar-nav .nav-link.show,
+.navbar-light .navbar-nav .show>.nav-link {
+ color:#fff
+}
+.navbar-light .navbar-toggler {
+ color:rgba(255,255,255,.6);
+ border-color:rgba(34,34,34,.1)
+}
+.navbar-light .navbar-toggler-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.6%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")
+}
+.navbar-light .navbar-text {
+ color:rgba(255,255,255,.6)
+}
+.navbar-light .navbar-text a {
+ color:#fff
+}
+.navbar-light .navbar-text a:focus,
+.navbar-light .navbar-text a:hover {
+ color:#fff
+}
+.navbar-dark .navbar-brand {
+ color:#fff
+}
+.navbar-dark .navbar-brand:focus,
+.navbar-dark .navbar-brand:hover {
+ color:#fff
+}
+.navbar-dark .navbar-nav .nav-link {
+ color:rgba(255,255,255,.6)
+}
+.navbar-dark .navbar-nav .nav-link:focus,
+.navbar-dark .navbar-nav .nav-link:hover {
+ color:#fff
+}
+.navbar-dark .navbar-nav .nav-link.disabled {
+ color:rgba(255,255,255,.25)
+}
+.navbar-dark .navbar-nav .active>.nav-link,
+.navbar-dark .navbar-nav .nav-link.active,
+.navbar-dark .navbar-nav .nav-link.show,
+.navbar-dark .navbar-nav .show>.nav-link {
+ color:#fff
+}
+.navbar-dark .navbar-toggler {
+ color:rgba(255,255,255,.6);
+ border-color:rgba(255,255,255,.1)
+}
+.navbar-dark .navbar-toggler-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.6%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")
+}
+.navbar-dark .navbar-text {
+ color:rgba(255,255,255,.6)
+}
+.navbar-dark .navbar-text a {
+ color:#fff
+}
+.navbar-dark .navbar-text a:focus,
+.navbar-dark .navbar-text a:hover {
+ color:#fff
+}
+.card {
+ position:relative;
+ display:flex;
+ flex-direction:column;
+ min-width:0;
+ word-wrap:break-word;
+ background-color:#303030;
+ background-clip:border-box;
+ border:1px solid rgba(0,0,0,.125);
+ border-radius:.25rem
+}
+.card>hr {
+ margin-right:0;
+ margin-left:0
+}
+.card>.list-group {
+ border-top:inherit;
+ border-bottom:inherit
+}
+.card>.list-group:first-child {
+ border-top-width:0;
+ border-top-left-radius:calc(.25rem - 1px);
+ border-top-right-radius:calc(.25rem - 1px)
+}
+.card>.list-group:last-child {
+ border-bottom-width:0;
+ border-bottom-right-radius:calc(.25rem - 1px);
+ border-bottom-left-radius:calc(.25rem - 1px)
+}
+.card-body {
+ flex:1 1 auto;
+ min-height:1px;
+ padding:1.25rem
+}
+.card-title {
+ margin-bottom:.75rem
+}
+.card-subtitle {
+ margin-top:-.375rem;
+ margin-bottom:0
+}
+.card-text:last-child {
+ margin-bottom:0
+}
+.card-link:hover {
+ text-decoration:none
+}
+.card-link+.card-link {
+ margin-left:1.25rem
+}
+.card-header {
+ padding:.75rem 1.25rem;
+ margin-bottom:0;
+ background-color:#444;
+ border-bottom:1px solid rgba(0,0,0,.125)
+}
+.card-header:first-child {
+ border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0
+}
+.card-header+.list-group .list-group-item:first-child {
+ border-top:0
+}
+.card-footer {
+ padding:.75rem 1.25rem;
+ background-color:#444;
+ border-top:1px solid rgba(0,0,0,.125)
+}
+.card-footer:last-child {
+ border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)
+}
+.card-header-tabs {
+ margin-right:-.625rem;
+ margin-bottom:-.75rem;
+ margin-left:-.625rem;
+ border-bottom:0
+}
+.card-header-pills {
+ margin-right:-.625rem;
+ margin-left:-.625rem
+}
+.card-img-overlay {
+ position:absolute;
+ top:0;
+ right:0;
+ bottom:0;
+ left:0;
+ padding:1.25rem
+}
+.card-img,
+.card-img-bottom,
+.card-img-top {
+ flex-shrink:0;
+ width:100%
+}
+.card-img,
+.card-img-top {
+ border-top-left-radius:calc(.25rem - 1px);
+ border-top-right-radius:calc(.25rem - 1px)
+}
+.card-img,
+.card-img-bottom {
+ border-bottom-right-radius:calc(.25rem - 1px);
+ border-bottom-left-radius:calc(.25rem - 1px)
+}
+.card-deck .card {
+ margin-bottom:15px
+}
+@media (min-width:576px) {
+ .card-deck {
+  display:flex;
+  flex-flow:row wrap;
+  margin-right:-15px;
+  margin-left:-15px
+ }
+ .card-deck .card {
+  flex:1 0 0%;
+  margin-right:15px;
+  margin-bottom:0;
+  margin-left:15px
+ }
+}
+.card-group>.card {
+ margin-bottom:15px
+}
+@media (min-width:576px) {
+ .card-group {
+  display:flex;
+  flex-flow:row wrap
+ }
+ .card-group>.card {
+  flex:1 0 0%;
+  margin-bottom:0
+ }
+ .card-group>.card+.card {
+  margin-left:0;
+  border-left:0
+ }
+ .card-group>.card:not(:last-child) {
+  border-top-right-radius:0;
+  border-bottom-right-radius:0
+ }
+ .card-group>.card:not(:last-child) .card-header,
+ .card-group>.card:not(:last-child) .card-img-top {
+  border-top-right-radius:0
+ }
+ .card-group>.card:not(:last-child) .card-footer,
+ .card-group>.card:not(:last-child) .card-img-bottom {
+  border-bottom-right-radius:0
+ }
+ .card-group>.card:not(:first-child) {
+  border-top-left-radius:0;
+  border-bottom-left-radius:0
+ }
+ .card-group>.card:not(:first-child) .card-header,
+ .card-group>.card:not(:first-child) .card-img-top {
+  border-top-left-radius:0
+ }
+ .card-group>.card:not(:first-child) .card-footer,
+ .card-group>.card:not(:first-child) .card-img-bottom {
+  border-bottom-left-radius:0
+ }
+}
+.card-columns .card {
+ margin-bottom:.75rem
+}
+@media (min-width:576px) {
+ .card-columns {
+  column-count:3;
+  column-gap:1.25rem;
+  orphans:1;
+  widows:1
+ }
+ .card-columns .card {
+  display:inline-block;
+  width:100%
+ }
+}
+.accordion>.card {
+ overflow:hidden
+}
+.accordion>.card:not(:last-of-type) {
+ border-bottom:0;
+ border-bottom-right-radius:0;
+ border-bottom-left-radius:0
+}
+.accordion>.card:not(:first-of-type) {
+ border-top-left-radius:0;
+ border-top-right-radius:0
+}
+.accordion>.card>.card-header {
+ border-radius:0;
+ margin-bottom:-1px
+}
+.breadcrumb {
+ display:flex;
+ flex-wrap:wrap;
+ padding:.75rem 1rem;
+ margin-bottom:1rem;
+ list-style:none;
+ background-color:#444;
+ border-radius:.25rem
+}
+.breadcrumb-item {
+ display:flex
+}
+.breadcrumb-item+.breadcrumb-item {
+ padding-left:.5rem
+}
+.breadcrumb-item+.breadcrumb-item::before {
+ display:inline-block;
+ padding-right:.5rem;
+ color:#888;
+ content:"/"
+}
+.breadcrumb-item+.breadcrumb-item:hover::before {
+ text-decoration:underline
+}
+.breadcrumb-item+.breadcrumb-item:hover::before {
+ text-decoration:none
+}
+.breadcrumb-item.active {
+ color:#888
+}
+.pagination {
+ display:flex;
+ padding-left:0;
+ list-style:none;
+ border-radius:.25rem
+}
+.page-link {
+ position:relative;
+ display:block;
+ padding:.5rem .75rem;
+ margin-left:0;
+ line-height:1.25;
+ color:#fff;
+ background-color:#e74c3c;
+ border:0 solid transparent
+}
+.page-link:hover {
+ z-index:2;
+ color:#fff;
+ text-decoration:none;
+ background-color:#a62f22;
+ border-color:transparent
+}
+.page-link:focus {
+ z-index:3;
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.25)
+}
+.page-item:first-child .page-link {
+ margin-left:0;
+ border-top-left-radius:.25rem;
+ border-bottom-left-radius:.25rem
+}
+.page-item:last-child .page-link {
+ border-top-right-radius:.25rem;
+ border-bottom-right-radius:.25rem
+}
+.page-item.active .page-link {
+ z-index:3;
+ color:#fff;
+ background-color:#00efb2;
+ border-color:transparent
+}
+.page-item.disabled .page-link {
+ color:#fff;
+ pointer-events:none;
+ cursor:auto;
+ background-color:#007053;
+ border-color:transparent
+}
+.pagination-lg .page-link {
+ padding:.75rem 1.5rem;
+ font-size:1.17188rem;
+ line-height:1.5
+}
+.pagination-lg .page-item:first-child .page-link {
+ border-top-left-radius:.3rem;
+ border-bottom-left-radius:.3rem
+}
+.pagination-lg .page-item:last-child .page-link {
+ border-top-right-radius:.3rem;
+ border-bottom-right-radius:.3rem
+}
+.pagination-sm .page-link {
+ padding:.25rem .5rem;
+ font-size:.82031rem;
+ line-height:1.5
+}
+.pagination-sm .page-item:first-child .page-link {
+ border-top-left-radius:.2rem;
+ border-bottom-left-radius:.2rem
+}
+.pagination-sm .page-item:last-child .page-link {
+ border-top-right-radius:.2rem;
+ border-bottom-right-radius:.2rem
+}
+.badge {
+ display:inline-block;
+ padding:.25em .4em;
+ font-size:75%;
+ font-weight:700;
+ line-height:1;
+ text-align:center;
+ white-space:nowrap;
+ vertical-align:baseline;
+ border-radius:.25rem;
+ transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .badge {
+  transition:none
+ }
+}
+a.badge:focus,
+a.badge:hover {
+ text-decoration:none
+}
+.badge:empty {
+ display:none
+}
+.btn .badge {
+ position:relative;
+ top:-1px
+}
+.badge-pill {
+ padding-right:.6em;
+ padding-left:.6em;
+ border-radius:10rem
+}
+.badge-primary {
+ color:#fff;
+ background-color:#375a7f
+}
+a.badge-primary:focus,
+a.badge-primary:hover {
+ color:#fff;
+ background-color:#28415b
+}
+a.badge-primary.focus,
+a.badge-primary:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(55,90,127,.5)
+}
+.badge-secondary {
+ color:#fff;
+ background-color:#444
+}
+a.badge-secondary:focus,
+a.badge-secondary:hover {
+ color:#fff;
+ background-color:#2b2b2b
+}
+a.badge-secondary.focus,
+a.badge-secondary:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(68,68,68,.5)
+}
+.badge-success {
+ color:#fff;
+ background-color:#00bc8c
+}
+a.badge-success:focus,
+a.badge-success:hover {
+ color:#fff;
+ background-color:#008966
+}
+a.badge-success.focus,
+a.badge-success:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(0,188,140,.5)
+}
+.badge-info {
+ color:#fff;
+ background-color:#3498db
+}
+a.badge-info:focus,
+a.badge-info:hover {
+ color:#fff;
+ background-color:#217dbb
+}
+a.badge-info.focus,
+a.badge-info:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(52,152,219,.5)
+}
+.badge-warning {
+ color:#fff;
+ background-color:#f39c12
+}
+a.badge-warning:focus,
+a.badge-warning:hover {
+ color:#fff;
+ background-color:#c87f0a
+}
+a.badge-warning.focus,
+a.badge-warning:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(243,156,18,.5)
+}
+.badge-danger {
+ color:#fff;
+ background-color:#e74c3c
+}
+a.badge-danger:focus,
+a.badge-danger:hover {
+ color:#fff;
+ background-color:#d62c1a
+}
+a.badge-danger.focus,
+a.badge-danger:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(231,76,60,.5)
+}
+.badge-light {
+ color:#fff;
+ background-color:#303030
+}
+a.badge-light:focus,
+a.badge-light:hover {
+ color:#fff;
+ background-color:#171717
+}
+a.badge-light.focus,
+a.badge-light:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(48,48,48,.5)
+}
+.badge-dark {
+ color:#222;
+ background-color:#dee2e6
+}
+a.badge-dark:focus,
+a.badge-dark:hover {
+ color:#222;
+ background-color:#c1c9d0
+}
+a.badge-dark.focus,
+a.badge-dark:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(222,226,230,.5)
+}
+.jumbotron {
+ padding:2rem 1rem;
+ margin-bottom:2rem;
+ background-color:#303030;
+ border-radius:.3rem
+}
+@media (min-width:576px) {
+ .jumbotron {
+  padding:4rem 2rem
+ }
+}
+.jumbotron-fluid {
+ padding-right:0;
+ padding-left:0;
+ border-radius:0
+}
+.alert {
+ position:relative;
+ padding:.75rem 1.25rem;
+ margin-bottom:1rem;
+ border:1px solid transparent;
+ border-radius:.25rem
+}
+.alert-heading {
+ color:inherit
+}
+.alert-link {
+ font-weight:700
+}
+.alert-dismissible {
+ padding-right:3.90625rem
+}
+.alert-dismissible .close {
+ position:absolute;
+ top:0;
+ right:0;
+ padding:.75rem 1.25rem;
+ color:inherit
+}
+.alert-primary {
+ color:#1d2f42;
+ background-color:#d7dee5;
+ border-color:#c7d1db
+}
+.alert-primary hr {
+ border-top-color:#b7c4d1
+}
+.alert-primary .alert-link {
+ color:#0d161f
+}
+.alert-secondary {
+ color:#232323;
+ background-color:#dadada;
+ border-color:#cbcbcb
+}
+.alert-secondary hr {
+ border-top-color:#bebebe
+}
+.alert-secondary .alert-link {
+ color:#0a0a0a
+}
+.alert-success {
+ color:#006249;
+ background-color:#ccf2e8;
+ border-color:#b8ecdf
+}
+.alert-success hr {
+ border-top-color:#a4e7d6
+}
+.alert-success .alert-link {
+ color:#002f23
+}
+.alert-info {
+ color:#1b4f72;
+ background-color:#d6eaf8;
+ border-color:#c6e2f5
+}
+.alert-info hr {
+ border-top-color:#b0d7f1
+}
+.alert-info .alert-link {
+ color:#113249
+}
+.alert-warning {
+ color:#7e5109;
+ background-color:#fdebd0;
+ border-color:#fce3bd
+}
+.alert-warning hr {
+ border-top-color:#fbd9a5
+}
+.alert-warning .alert-link {
+ color:#4e3206
+}
+.alert-danger {
+ color:#78281f;
+ background-color:#fadbd8;
+ border-color:#f8cdc8
+}
+.alert-danger hr {
+ border-top-color:#f5b8b1
+}
+.alert-danger .alert-link {
+ color:#4f1a15
+}
+.alert-light {
+ color:#191919;
+ background-color:#d6d6d6;
+ border-color:#c5c5c5
+}
+.alert-light hr {
+ border-top-color:#b8b8b8
+}
+.alert-light .alert-link {
+ color:#000
+}
+.alert-dark {
+ color:#737678;
+ background-color:#f8f9fa;
+ border-color:#f6f7f8
+}
+.alert-dark hr {
+ border-top-color:#e8eaed
+}
+.alert-dark .alert-link {
+ color:#5a5c5e
+}
+@keyframes progress-bar-stripes {
+ from {
+  background-position:1rem 0
+ }
+ to {
+  background-position:0 0
+ }
+}
+.progress {
+ display:flex;
+ height:1rem;
+ overflow:hidden;
+ line-height:0;
+ font-size:.70312rem;
+ background-color:#444;
+ border-radius:.25rem
+}
+.progress-bar {
+ display:flex;
+ flex-direction:column;
+ justify-content:center;
+ overflow:hidden;
+ color:#fff;
+ text-align:center;
+ white-space:nowrap;
+ background-color:#375a7f;
+ transition:width .6s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .progress-bar {
+  transition:none
+ }
+}
+.progress-bar-striped {
+ background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);
+ background-size:1rem 1rem
+}
+.progress-bar-animated {
+ animation:progress-bar-stripes 1s linear infinite
+}
+@media (prefers-reduced-motion:reduce) {
+ .progress-bar-animated {
+  animation:none
+ }
+}
+.media {
+ display:flex;
+ align-items:flex-start
+}
+.media-body {
+ flex:1
+}
+.list-group {
+ display:flex;
+ flex-direction:column;
+ padding-left:0;
+ margin-bottom:0;
+ border-radius:.25rem
+}
+.list-group-item-action {
+ width:100%;
+ color:#444;
+ text-align:inherit
+}
+.list-group-item-action:focus,
+.list-group-item-action:hover {
+ z-index:1;
+ color:#444;
+ text-decoration:none;
+ background-color:#444
+}
+.list-group-item-action:active {
+ color:#dee2e6;
+ background-color:#ebebeb
+}
+.list-group-item {
+ position:relative;
+ display:block;
+ padding:.75rem 1.25rem;
+ background-color:#303030;
+ border:1px solid #444
+}
+.list-group-item:first-child {
+ border-top-left-radius:inherit;
+ border-top-right-radius:inherit
+}
+.list-group-item:last-child {
+ border-bottom-right-radius:inherit;
+ border-bottom-left-radius:inherit
+}
+.list-group-item.disabled,
+.list-group-item:disabled {
+ color:#888;
+ pointer-events:none;
+ background-color:#303030
+}
+.list-group-item.active {
+ z-index:2;
+ color:#fff;
+ background-color:#375a7f;
+ border-color:#375a7f
+}
+.list-group-item+.list-group-item {
+ border-top-width:0
+}
+.list-group-item+.list-group-item.active {
+ margin-top:-1px;
+ border-top-width:1px
+}
+.list-group-horizontal {
+ flex-direction:row
+}
+.list-group-horizontal>.list-group-item:first-child {
+ border-bottom-left-radius:.25rem;
+ border-top-right-radius:0
+}
+.list-group-horizontal>.list-group-item:last-child {
+ border-top-right-radius:.25rem;
+ border-bottom-left-radius:0
+}
+.list-group-horizontal>.list-group-item.active {
+ margin-top:0
+}
+.list-group-horizontal>.list-group-item+.list-group-item {
+ border-top-width:1px;
+ border-left-width:0
+}
+.list-group-horizontal>.list-group-item+.list-group-item.active {
+ margin-left:-1px;
+ border-left-width:1px
+}
+@media (min-width:576px) {
+ .list-group-horizontal-sm {
+  flex-direction:row
+ }
+ .list-group-horizontal-sm>.list-group-item:first-child {
+  border-bottom-left-radius:.25rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-sm>.list-group-item:last-child {
+  border-top-right-radius:.25rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-sm>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-sm>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-sm>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+@media (min-width:768px) {
+ .list-group-horizontal-md {
+  flex-direction:row
+ }
+ .list-group-horizontal-md>.list-group-item:first-child {
+  border-bottom-left-radius:.25rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-md>.list-group-item:last-child {
+  border-top-right-radius:.25rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-md>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-md>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-md>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+@media (min-width:992px) {
+ .list-group-horizontal-lg {
+  flex-direction:row
+ }
+ .list-group-horizontal-lg>.list-group-item:first-child {
+  border-bottom-left-radius:.25rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-lg>.list-group-item:last-child {
+  border-top-right-radius:.25rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-lg>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-lg>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-lg>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+@media (min-width:1200px) {
+ .list-group-horizontal-xl {
+  flex-direction:row
+ }
+ .list-group-horizontal-xl>.list-group-item:first-child {
+  border-bottom-left-radius:.25rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-xl>.list-group-item:last-child {
+  border-top-right-radius:.25rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-xl>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-xl>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-xl>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+.list-group-flush {
+ border-radius:0
+}
+.list-group-flush>.list-group-item {
+ border-width:0 0 1px
+}
+.list-group-flush>.list-group-item:last-child {
+ border-bottom-width:0
+}
+.list-group-item-primary {
+ color:#1d2f42;
+ background-color:#c7d1db
+}
+.list-group-item-primary.list-group-item-action:focus,
+.list-group-item-primary.list-group-item-action:hover {
+ color:#1d2f42;
+ background-color:#b7c4d1
+}
+.list-group-item-primary.list-group-item-action.active {
+ color:#fff;
+ background-color:#1d2f42;
+ border-color:#1d2f42
+}
+.list-group-item-secondary {
+ color:#232323;
+ background-color:#cbcbcb
+}
+.list-group-item-secondary.list-group-item-action:focus,
+.list-group-item-secondary.list-group-item-action:hover {
+ color:#232323;
+ background-color:#bebebe
+}
+.list-group-item-secondary.list-group-item-action.active {
+ color:#fff;
+ background-color:#232323;
+ border-color:#232323
+}
+.list-group-item-success {
+ color:#006249;
+ background-color:#b8ecdf
+}
+.list-group-item-success.list-group-item-action:focus,
+.list-group-item-success.list-group-item-action:hover {
+ color:#006249;
+ background-color:#a4e7d6
+}
+.list-group-item-success.list-group-item-action.active {
+ color:#fff;
+ background-color:#006249;
+ border-color:#006249
+}
+.list-group-item-info {
+ color:#1b4f72;
+ background-color:#c6e2f5
+}
+.list-group-item-info.list-group-item-action:focus,
+.list-group-item-info.list-group-item-action:hover {
+ color:#1b4f72;
+ background-color:#b0d7f1
+}
+.list-group-item-info.list-group-item-action.active {
+ color:#fff;
+ background-color:#1b4f72;
+ border-color:#1b4f72
+}
+.list-group-item-warning {
+ color:#7e5109;
+ background-color:#fce3bd
+}
+.list-group-item-warning.list-group-item-action:focus,
+.list-group-item-warning.list-group-item-action:hover {
+ color:#7e5109;
+ background-color:#fbd9a5
+}
+.list-group-item-warning.list-group-item-action.active {
+ color:#fff;
+ background-color:#7e5109;
+ border-color:#7e5109
+}
+.list-group-item-danger {
+ color:#78281f;
+ background-color:#f8cdc8
+}
+.list-group-item-danger.list-group-item-action:focus,
+.list-group-item-danger.list-group-item-action:hover {
+ color:#78281f;
+ background-color:#f5b8b1
+}
+.list-group-item-danger.list-group-item-action.active {
+ color:#fff;
+ background-color:#78281f;
+ border-color:#78281f
+}
+.list-group-item-light {
+ color:#191919;
+ background-color:#c5c5c5
+}
+.list-group-item-light.list-group-item-action:focus,
+.list-group-item-light.list-group-item-action:hover {
+ color:#191919;
+ background-color:#b8b8b8
+}
+.list-group-item-light.list-group-item-action.active {
+ color:#fff;
+ background-color:#191919;
+ border-color:#191919
+}
+.list-group-item-dark {
+ color:#737678;
+ background-color:#f6f7f8
+}
+.list-group-item-dark.list-group-item-action:focus,
+.list-group-item-dark.list-group-item-action:hover {
+ color:#737678;
+ background-color:#e8eaed
+}
+.list-group-item-dark.list-group-item-action.active {
+ color:#fff;
+ background-color:#737678;
+ border-color:#737678
+}
+.close {
+ float:right;
+ font-size:1.40625rem;
+ font-weight:700;
+ line-height:1;
+ color:#fff;
+ text-shadow:none;
+ opacity:.5
+}
+.close:hover {
+ color:#fff;
+ text-decoration:none
+}
+.close:not(:disabled):not(.disabled):focus,
+.close:not(:disabled):not(.disabled):hover {
+ opacity:.75
+}
+button.close {
+ padding:0;
+ background-color:transparent;
+ border:0
+}
+a.close.disabled {
+ pointer-events:none
+}
+.toast {
+ max-width:350px;
+ overflow:hidden;
+ font-size:.875rem;
+ background-color:#444;
+ background-clip:padding-box;
+ border:1px solid rgba(0,0,0,.1);
+ box-shadow:0 .25rem .75rem rgba(0,0,0,.1);
+ backdrop-filter:blur(10px);
+ opacity:0;
+ border-radius:.25rem
+}
+.toast:not(:last-child) {
+ margin-bottom:.75rem
+}
+.toast.showing {
+ opacity:1
+}
+.toast.show {
+ display:block;
+ opacity:1
+}
+.toast.hide {
+ display:none
+}
+.toast-header {
+ display:flex;
+ align-items:center;
+ padding:.25rem .75rem;
+ color:#888;
+ background-color:#303030;
+ background-clip:padding-box;
+ border-bottom:1px solid rgba(0,0,0,.05)
+}
+.toast-body {
+ padding:.75rem
+}
+.modal-open {
+ overflow:hidden
+}
+.modal-open .modal {
+ overflow-x:hidden;
+ overflow-y:auto
+}
+.modal {
+ position:fixed;
+ top:0;
+ left:0;
+ z-index:1050;
+ display:none;
+ width:100%;
+ height:100%;
+ overflow:hidden;
+ outline:0
+}
+.modal-dialog {
+ position:relative;
+ width:auto;
+ margin:.5rem;
+ pointer-events:none
+}
+.modal.fade .modal-dialog {
+ transition:transform .3s ease-out;
+ transform:translate(0,-50px)
+}
+@media (prefers-reduced-motion:reduce) {
+ .modal.fade .modal-dialog {
+  transition:none
+ }
+}
+.modal.show .modal-dialog {
+ transform:none
+}
+.modal.modal-static .modal-dialog {
+ transform:scale(1.02)
+}
+.modal-dialog-scrollable {
+ display:flex;
+ max-height:calc(100% - 1rem)
+}
+.modal-dialog-scrollable .modal-content {
+ max-height:calc(100vh - 1rem);
+ overflow:hidden
+}
+.modal-dialog-scrollable .modal-footer,
+.modal-dialog-scrollable .modal-header {
+ flex-shrink:0
+}
+.modal-dialog-scrollable .modal-body {
+ overflow-y:auto
+}
+.modal-dialog-centered {
+ display:flex;
+ align-items:center;
+ min-height:calc(100% - 1rem)
+}
+.modal-dialog-centered::before {
+ display:block;
+ height:calc(100vh - 1rem);
+ height:min-content;
+ content:""
+}
+.modal-dialog-centered.modal-dialog-scrollable {
+ flex-direction:column;
+ justify-content:center;
+ height:100%
+}
+.modal-dialog-centered.modal-dialog-scrollable .modal-content {
+ max-height:none
+}
+.modal-dialog-centered.modal-dialog-scrollable::before {
+ content:none
+}
+.modal-content {
+ position:relative;
+ display:flex;
+ flex-direction:column;
+ width:100%;
+ pointer-events:auto;
+ background-color:#303030;
+ background-clip:padding-box;
+ border:1px solid #444;
+ border-radius:.3rem;
+ outline:0
+}
+.modal-backdrop {
+ position:fixed;
+ top:0;
+ left:0;
+ z-index:1040;
+ width:100vw;
+ height:100vh;
+ background-color:#000
+}
+.modal-backdrop.fade {
+ opacity:0
+}
+.modal-backdrop.show {
+ opacity:.5
+}
+.modal-header {
+ display:flex;
+ align-items:flex-start;
+ justify-content:space-between;
+ padding:1rem 1rem;
+ border-bottom:1px solid #444;
+ border-top-left-radius:calc(.3rem - 1px);
+ border-top-right-radius:calc(.3rem - 1px)
+}
+.modal-header .close {
+ padding:1rem 1rem;
+ margin:-1rem -1rem -1rem auto
+}
+.modal-title {
+ margin-bottom:0;
+ line-height:1.5
+}
+.modal-body {
+ position:relative;
+ flex:1 1 auto;
+ padding:1rem
+}
+.modal-footer {
+ display:flex;
+ flex-wrap:wrap;
+ align-items:center;
+ justify-content:flex-end;
+ padding:.75rem;
+ border-top:1px solid #444;
+ border-bottom-right-radius:calc(.3rem - 1px);
+ border-bottom-left-radius:calc(.3rem - 1px)
+}
+.modal-footer>* {
+ margin:.25rem
+}
+.modal-scrollbar-measure {
+ position:absolute;
+ top:-9999px;
+ width:50px;
+ height:50px;
+ overflow:scroll
+}
+@media (min-width:576px) {
+ .modal-dialog {
+  max-width:500px;
+  margin:1.75rem auto
+ }
+ .modal-dialog-scrollable {
+  max-height:calc(100% - 3.5rem)
+ }
+ .modal-dialog-scrollable .modal-content {
+  max-height:calc(100vh - 3.5rem)
+ }
+ .modal-dialog-centered {
+  min-height:calc(100% - 3.5rem)
+ }
+ .modal-dialog-centered::before {
+  height:calc(100vh - 3.5rem);
+  height:min-content
+ }
+ .modal-sm {
+  max-width:300px
+ }
+}
+@media (min-width:992px) {
+ .modal-lg,
+ .modal-xl {
+  max-width:800px
+ }
+}
+@media (min-width:1200px) {
+ .modal-xl {
+  max-width:1140px
+ }
+}
+.tooltip {
+ position:absolute;
+ z-index:1070;
+ display:block;
+ margin:0;
+ font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
+ font-style:normal;
+ font-weight:400;
+ line-height:1.5;
+ text-align:left;
+ text-align:start;
+ text-decoration:none;
+ text-shadow:none;
+ text-transform:none;
+ letter-spacing:normal;
+ word-break:normal;
+ word-spacing:normal;
+ white-space:normal;
+ line-break:auto;
+ font-size:.82031rem;
+ word-wrap:break-word;
+ opacity:0
+}
+.tooltip.show {
+ opacity:.9
+}
+.tooltip .arrow {
+ position:absolute;
+ display:block;
+ width:.8rem;
+ height:.4rem
+}
+.tooltip .arrow::before {
+ position:absolute;
+ content:"";
+ border-color:transparent;
+ border-style:solid
+}
+.bs-tooltip-auto[x-placement^=top],
+.bs-tooltip-top {
+ padding:.4rem 0
+}
+.bs-tooltip-auto[x-placement^=top] .arrow,
+.bs-tooltip-top .arrow {
+ bottom:0
+}
+.bs-tooltip-auto[x-placement^=top] .arrow::before,
+.bs-tooltip-top .arrow::before {
+ top:0;
+ border-width:.4rem .4rem 0;
+ border-top-color:#000
+}
+.bs-tooltip-auto[x-placement^=right],
+.bs-tooltip-right {
+ padding:0 .4rem
+}
+.bs-tooltip-auto[x-placement^=right] .arrow,
+.bs-tooltip-right .arrow {
+ left:0;
+ width:.4rem;
+ height:.8rem
+}
+.bs-tooltip-auto[x-placement^=right] .arrow::before,
+.bs-tooltip-right .arrow::before {
+ right:0;
+ border-width:.4rem .4rem .4rem 0;
+ border-right-color:#000
+}
+.bs-tooltip-auto[x-placement^=bottom],
+.bs-tooltip-bottom {
+ padding:.4rem 0
+}
+.bs-tooltip-auto[x-placement^=bottom] .arrow,
+.bs-tooltip-bottom .arrow {
+ top:0
+}
+.bs-tooltip-auto[x-placement^=bottom] .arrow::before,
+.bs-tooltip-bottom .arrow::before {
+ bottom:0;
+ border-width:0 .4rem .4rem;
+ border-bottom-color:#000
+}
+.bs-tooltip-auto[x-placement^=left],
+.bs-tooltip-left {
+ padding:0 .4rem
+}
+.bs-tooltip-auto[x-placement^=left] .arrow,
+.bs-tooltip-left .arrow {
+ right:0;
+ width:.4rem;
+ height:.8rem
+}
+.bs-tooltip-auto[x-placement^=left] .arrow::before,
+.bs-tooltip-left .arrow::before {
+ left:0;
+ border-width:.4rem 0 .4rem .4rem;
+ border-left-color:#000
+}
+.tooltip-inner {
+ max-width:200px;
+ padding:.25rem .5rem;
+ color:#fff;
+ text-align:center;
+ background-color:#000;
+ border-radius:.25rem
+}
+.popover {
+ position:absolute;
+ top:0;
+ left:0;
+ z-index:1060;
+ display:block;
+ max-width:276px;
+ font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";
+ font-style:normal;
+ font-weight:400;
+ line-height:1.5;
+ text-align:left;
+ text-align:start;
+ text-decoration:none;
+ text-shadow:none;
+ text-transform:none;
+ letter-spacing:normal;
+ word-break:normal;
+ word-spacing:normal;
+ white-space:normal;
+ line-break:auto;
+ font-size:.82031rem;
+ word-wrap:break-word;
+ background-color:#303030;
+ background-clip:padding-box;
+ border:1px solid rgba(0,0,0,.2);
+ border-radius:.3rem
+}
+.popover .arrow {
+ position:absolute;
+ display:block;
+ width:1rem;
+ height:.5rem;
+ margin:0 .3rem
+}
+.popover .arrow::after,
+.popover .arrow::before {
+ position:absolute;
+ display:block;
+ content:"";
+ border-color:transparent;
+ border-style:solid
+}
+.bs-popover-auto[x-placement^=top],
+.bs-popover-top {
+ margin-bottom:.5rem
+}
+.bs-popover-auto[x-placement^=top]>.arrow,
+.bs-popover-top>.arrow {
+ bottom:calc(-.5rem - 1px)
+}
+.bs-popover-auto[x-placement^=top]>.arrow::before,
+.bs-popover-top>.arrow::before {
+ bottom:0;
+ border-width:.5rem .5rem 0;
+ border-top-color:rgba(0,0,0,.25)
+}
+.bs-popover-auto[x-placement^=top]>.arrow::after,
+.bs-popover-top>.arrow::after {
+ bottom:1px;
+ border-width:.5rem .5rem 0;
+ border-top-color:#303030
+}
+.bs-popover-auto[x-placement^=right],
+.bs-popover-right {
+ margin-left:.5rem
+}
+.bs-popover-auto[x-placement^=right]>.arrow,
+.bs-popover-right>.arrow {
+ left:calc(-.5rem - 1px);
+ width:.5rem;
+ height:1rem;
+ margin:.3rem 0
+}
+.bs-popover-auto[x-placement^=right]>.arrow::before,
+.bs-popover-right>.arrow::before {
+ left:0;
+ border-width:.5rem .5rem .5rem 0;
+ border-right-color:rgba(0,0,0,.25)
+}
+.bs-popover-auto[x-placement^=right]>.arrow::after,
+.bs-popover-right>.arrow::after {
+ left:1px;
+ border-width:.5rem .5rem .5rem 0;
+ border-right-color:#303030
+}
+.bs-popover-auto[x-placement^=bottom],
+.bs-popover-bottom {
+ margin-top:.5rem
+}
+.bs-popover-auto[x-placement^=bottom]>.arrow,
+.bs-popover-bottom>.arrow {
+ top:calc(-.5rem - 1px)
+}
+.bs-popover-auto[x-placement^=bottom]>.arrow::before,
+.bs-popover-bottom>.arrow::before {
+ top:0;
+ border-width:0 .5rem .5rem .5rem;
+ border-bottom-color:rgba(0,0,0,.25)
+}
+.bs-popover-auto[x-placement^=bottom]>.arrow::after,
+.bs-popover-bottom>.arrow::after {
+ top:1px;
+ border-width:0 .5rem .5rem .5rem;
+ border-bottom-color:#303030
+}
+.bs-popover-auto[x-placement^=bottom] .popover-header::before,
+.bs-popover-bottom .popover-header::before {
+ position:absolute;
+ top:0;
+ left:50%;
+ display:block;
+ width:1rem;
+ margin-left:-.5rem;
+ content:"";
+ border-bottom:1px solid #444
+}
+.bs-popover-auto[x-placement^=left],
+.bs-popover-left {
+ margin-right:.5rem
+}
+.bs-popover-auto[x-placement^=left]>.arrow,
+.bs-popover-left>.arrow {
+ right:calc(-.5rem - 1px);
+ width:.5rem;
+ height:1rem;
+ margin:.3rem 0
+}
+.bs-popover-auto[x-placement^=left]>.arrow::before,
+.bs-popover-left>.arrow::before {
+ right:0;
+ border-width:.5rem 0 .5rem .5rem;
+ border-left-color:rgba(0,0,0,.25)
+}
+.bs-popover-auto[x-placement^=left]>.arrow::after,
+.bs-popover-left>.arrow::after {
+ right:1px;
+ border-width:.5rem 0 .5rem .5rem;
+ border-left-color:#303030
+}
+.popover-header {
+ padding:.5rem .75rem;
+ margin-bottom:0;
+ font-size:.9375rem;
+ background-color:#444;
+ border-bottom:1px solid #373737;
+ border-top-left-radius:calc(.3rem - 1px);
+ border-top-right-radius:calc(.3rem - 1px)
+}
+.popover-header:empty {
+ display:none
+}
+.popover-body {
+ padding:.5rem .75rem;
+ color:#dee2e6
+}
+.carousel {
+ position:relative
+}
+.carousel.pointer-event {
+ touch-action:pan-y
+}
+.carousel-inner {
+ position:relative;
+ width:100%;
+ overflow:hidden
+}
+.carousel-inner::after {
+ display:block;
+ clear:both;
+ content:""
+}
+.carousel-item {
+ position:relative;
+ display:none;
+ float:left;
+ width:100%;
+ margin-right:-100%;
+ backface-visibility:hidden;
+ transition:transform .6s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-item {
+  transition:none
+ }
+}
+.carousel-item-next,
+.carousel-item-prev,
+.carousel-item.active {
+ display:block
+}
+.active.carousel-item-right,
+.carousel-item-next:not(.carousel-item-left) {
+ transform:translateX(100%)
+}
+.active.carousel-item-left,
+.carousel-item-prev:not(.carousel-item-right) {
+ transform:translateX(-100%)
+}
+.carousel-fade .carousel-item {
+ opacity:0;
+ transition-property:opacity;
+ transform:none
+}
+.carousel-fade .carousel-item-next.carousel-item-left,
+.carousel-fade .carousel-item-prev.carousel-item-right,
+.carousel-fade .carousel-item.active {
+ z-index:1;
+ opacity:1
+}
+.carousel-fade .active.carousel-item-left,
+.carousel-fade .active.carousel-item-right {
+ z-index:0;
+ opacity:0;
+ transition:opacity 0s .6s
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-fade .active.carousel-item-left,
+ .carousel-fade .active.carousel-item-right {
+  transition:none
+ }
+}
+.carousel-control-next,
+.carousel-control-prev {
+ position:absolute;
+ top:0;
+ bottom:0;
+ z-index:1;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ width:15%;
+ color:#fff;
+ text-align:center;
+ opacity:.5;
+ transition:opacity .15s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-control-next,
+ .carousel-control-prev {
+  transition:none
+ }
+}
+.carousel-control-next:focus,
+.carousel-control-next:hover,
+.carousel-control-prev:focus,
+.carousel-control-prev:hover {
+ color:#fff;
+ text-decoration:none;
+ outline:0;
+ opacity:.9
+}
+.carousel-control-prev {
+ left:0
+}
+.carousel-control-next {
+ right:0
+}
+.carousel-control-next-icon,
+.carousel-control-prev-icon {
+ display:inline-block;
+ width:20px;
+ height:20px;
+ background:no-repeat 50%/100% 100%
+}
+.carousel-control-prev-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")
+}
+.carousel-control-next-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")
+}
+.carousel-indicators {
+ position:absolute;
+ right:0;
+ bottom:0;
+ left:0;
+ z-index:15;
+ display:flex;
+ justify-content:center;
+ padding-left:0;
+ margin-right:15%;
+ margin-left:15%;
+ list-style:none
+}
+.carousel-indicators li {
+ box-sizing:content-box;
+ flex:0 1 auto;
+ width:30px;
+ height:3px;
+ margin-right:3px;
+ margin-left:3px;
+ text-indent:-999px;
+ cursor:pointer;
+ background-color:#fff;
+ background-clip:padding-box;
+ border-top:10px solid transparent;
+ border-bottom:10px solid transparent;
+ opacity:.5;
+ transition:opacity .6s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-indicators li {
+  transition:none
+ }
+}
+.carousel-indicators .active {
+ opacity:1
+}
+.carousel-caption {
+ position:absolute;
+ right:15%;
+ bottom:20px;
+ left:15%;
+ z-index:10;
+ padding-top:20px;
+ padding-bottom:20px;
+ color:#fff;
+ text-align:center
+}
+@keyframes spinner-border {
+ to {
+  transform:rotate(360deg)
+ }
+}
+.spinner-border {
+ display:inline-block;
+ width:2rem;
+ height:2rem;
+ vertical-align:text-bottom;
+ border:.25em solid currentColor;
+ border-right-color:transparent;
+ border-radius:50%;
+ animation:spinner-border .75s linear infinite
+}
+.spinner-border-sm {
+ width:1rem;
+ height:1rem;
+ border-width:.2em
+}
+@keyframes spinner-grow {
+ 0% {
+  transform:scale(0)
+ }
+ 50% {
+  opacity:1;
+  transform:none
+ }
+}
+.spinner-grow {
+ display:inline-block;
+ width:2rem;
+ height:2rem;
+ vertical-align:text-bottom;
+ background-color:currentColor;
+ border-radius:50%;
+ opacity:0;
+ animation:spinner-grow .75s linear infinite
+}
+.spinner-grow-sm {
+ width:1rem;
+ height:1rem
+}
+.align-baseline {
+ vertical-align:baseline!important
+}
+.align-top {
+ vertical-align:top!important
+}
+.align-middle {
+ vertical-align:middle!important
+}
+.align-bottom {
+ vertical-align:bottom!important
+}
+.align-text-bottom {
+ vertical-align:text-bottom!important
+}
+.align-text-top {
+ vertical-align:text-top!important
+}
+.bg-primary {
+ background-color:#375a7f!important
+}
+a.bg-primary:focus,
+a.bg-primary:hover,
+button.bg-primary:focus,
+button.bg-primary:hover {
+ background-color:#28415b!important
+}
+.bg-secondary {
+ background-color:#444!important
+}
+a.bg-secondary:focus,
+a.bg-secondary:hover,
+button.bg-secondary:focus,
+button.bg-secondary:hover {
+ background-color:#2b2b2b!important
+}
+.bg-success {
+ background-color:#00bc8c!important
+}
+a.bg-success:focus,
+a.bg-success:hover,
+button.bg-success:focus,
+button.bg-success:hover {
+ background-color:#008966!important
+}
+.bg-info {
+ background-color:#3498db!important
+}
+a.bg-info:focus,
+a.bg-info:hover,
+button.bg-info:focus,
+button.bg-info:hover {
+ background-color:#217dbb!important
+}
+.bg-warning {
+ background-color:#f39c12!important
+}
+a.bg-warning:focus,
+a.bg-warning:hover,
+button.bg-warning:focus,
+button.bg-warning:hover {
+ background-color:#c87f0a!important
+}
+.bg-danger {
+ background-color:#e74c3c!important
+}
+a.bg-danger:focus,
+a.bg-danger:hover,
+button.bg-danger:focus,
+button.bg-danger:hover {
+ background-color:#d62c1a!important
+}
+.bg-light {
+ background-color:#303030!important
+}
+a.bg-light:focus,
+a.bg-light:hover,
+button.bg-light:focus,
+button.bg-light:hover {
+ background-color:#171717!important
+}
+.bg-dark {
+ background-color:#dee2e6!important
+}
+a.bg-dark:focus,
+a.bg-dark:hover,
+button.bg-dark:focus,
+button.bg-dark:hover {
+ background-color:#c1c9d0!important
+}
+.bg-white {
+ background-color:#fff!important
+}
+.bg-transparent {
+ background-color:transparent!important
+}
+.border {
+ border:1px solid #dee2e6!important
+}
+.border-top {
+ border-top:1px solid #dee2e6!important
+}
+.border-right {
+ border-right:1px solid #dee2e6!important
+}
+.border-bottom {
+ border-bottom:1px solid #dee2e6!important
+}
+.border-left {
+ border-left:1px solid #dee2e6!important
+}
+.border-0 {
+ border:0!important
+}
+.border-top-0 {
+ border-top:0!important
+}
+.border-right-0 {
+ border-right:0!important
+}
+.border-bottom-0 {
+ border-bottom:0!important
+}
+.border-left-0 {
+ border-left:0!important
+}
+.border-primary {
+ border-color:#375a7f!important
+}
+.border-secondary {
+ border-color:#444!important
+}
+.border-success {
+ border-color:#00bc8c!important
+}
+.border-info {
+ border-color:#3498db!important
+}
+.border-warning {
+ border-color:#f39c12!important
+}
+.border-danger {
+ border-color:#e74c3c!important
+}
+.border-light {
+ border-color:#303030!important
+}
+.border-dark {
+ border-color:#dee2e6!important
+}
+.border-white {
+ border-color:#fff!important
+}
+.rounded-sm {
+ border-radius:.2rem!important
+}
+.rounded {
+ border-radius:.25rem!important
+}
+.rounded-top {
+ border-top-left-radius:.25rem!important;
+ border-top-right-radius:.25rem!important
+}
+.rounded-right {
+ border-top-right-radius:.25rem!important;
+ border-bottom-right-radius:.25rem!important
+}
+.rounded-bottom {
+ border-bottom-right-radius:.25rem!important;
+ border-bottom-left-radius:.25rem!important
+}
+.rounded-left {
+ border-top-left-radius:.25rem!important;
+ border-bottom-left-radius:.25rem!important
+}
+.rounded-lg {
+ border-radius:.3rem!important
+}
+.rounded-circle {
+ border-radius:50%!important
+}
+.rounded-pill {
+ border-radius:50rem!important
+}
+.rounded-0 {
+ border-radius:0!important
+}
+.clearfix::after {
+ display:block;
+ clear:both;
+ content:""
+}
+.d-none {
+ display:none!important
+}
+.d-inline {
+ display:inline!important
+}
+.d-inline-block {
+ display:inline-block!important
+}
+.d-block {
+ display:block!important
+}
+.d-table {
+ display:table!important
+}
+.d-table-row {
+ display:table-row!important
+}
+.d-table-cell {
+ display:table-cell!important
+}
+.d-flex {
+ display:flex!important
+}
+.d-inline-flex {
+ display:inline-flex!important
+}
+@media (min-width:576px) {
+ .d-sm-none {
+  display:none!important
+ }
+ .d-sm-inline {
+  display:inline!important
+ }
+ .d-sm-inline-block {
+  display:inline-block!important
+ }
+ .d-sm-block {
+  display:block!important
+ }
+ .d-sm-table {
+  display:table!important
+ }
+ .d-sm-table-row {
+  display:table-row!important
+ }
+ .d-sm-table-cell {
+  display:table-cell!important
+ }
+ .d-sm-flex {
+  display:flex!important
+ }
+ .d-sm-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media (min-width:768px) {
+ .d-md-none {
+  display:none!important
+ }
+ .d-md-inline {
+  display:inline!important
+ }
+ .d-md-inline-block {
+  display:inline-block!important
+ }
+ .d-md-block {
+  display:block!important
+ }
+ .d-md-table {
+  display:table!important
+ }
+ .d-md-table-row {
+  display:table-row!important
+ }
+ .d-md-table-cell {
+  display:table-cell!important
+ }
+ .d-md-flex {
+  display:flex!important
+ }
+ .d-md-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media (min-width:992px) {
+ .d-lg-none {
+  display:none!important
+ }
+ .d-lg-inline {
+  display:inline!important
+ }
+ .d-lg-inline-block {
+  display:inline-block!important
+ }
+ .d-lg-block {
+  display:block!important
+ }
+ .d-lg-table {
+  display:table!important
+ }
+ .d-lg-table-row {
+  display:table-row!important
+ }
+ .d-lg-table-cell {
+  display:table-cell!important
+ }
+ .d-lg-flex {
+  display:flex!important
+ }
+ .d-lg-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media (min-width:1200px) {
+ .d-xl-none {
+  display:none!important
+ }
+ .d-xl-inline {
+  display:inline!important
+ }
+ .d-xl-inline-block {
+  display:inline-block!important
+ }
+ .d-xl-block {
+  display:block!important
+ }
+ .d-xl-table {
+  display:table!important
+ }
+ .d-xl-table-row {
+  display:table-row!important
+ }
+ .d-xl-table-cell {
+  display:table-cell!important
+ }
+ .d-xl-flex {
+  display:flex!important
+ }
+ .d-xl-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media print {
+ .d-print-none {
+  display:none!important
+ }
+ .d-print-inline {
+  display:inline!important
+ }
+ .d-print-inline-block {
+  display:inline-block!important
+ }
+ .d-print-block {
+  display:block!important
+ }
+ .d-print-table {
+  display:table!important
+ }
+ .d-print-table-row {
+  display:table-row!important
+ }
+ .d-print-table-cell {
+  display:table-cell!important
+ }
+ .d-print-flex {
+  display:flex!important
+ }
+ .d-print-inline-flex {
+  display:inline-flex!important
+ }
+}
+.embed-responsive {
+ position:relative;
+ display:block;
+ width:100%;
+ padding:0;
+ overflow:hidden
+}
+.embed-responsive::before {
+ display:block;
+ content:""
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive embed,
+.embed-responsive iframe,
+.embed-responsive object,
+.embed-responsive video {
+ position:absolute;
+ top:0;
+ bottom:0;
+ left:0;
+ width:100%;
+ height:100%;
+ border:0
+}
+.embed-responsive-21by9::before {
+ padding-top:42.85714%
+}
+.embed-responsive-16by9::before {
+ padding-top:56.25%
+}
+.embed-responsive-4by3::before {
+ padding-top:75%
+}
+.embed-responsive-1by1::before {
+ padding-top:100%
+}
+.flex-row {
+ flex-direction:row!important
+}
+.flex-column {
+ flex-direction:column!important
+}
+.flex-row-reverse {
+ flex-direction:row-reverse!important
+}
+.flex-column-reverse {
+ flex-direction:column-reverse!important
+}
+.flex-wrap {
+ flex-wrap:wrap!important
+}
+.flex-nowrap {
+ flex-wrap:nowrap!important
+}
+.flex-wrap-reverse {
+ flex-wrap:wrap-reverse!important
+}
+.flex-fill {
+ flex:1 1 auto!important
+}
+.flex-grow-0 {
+ flex-grow:0!important
+}
+.flex-grow-1 {
+ flex-grow:1!important
+}
+.flex-shrink-0 {
+ flex-shrink:0!important
+}
+.flex-shrink-1 {
+ flex-shrink:1!important
+}
+.justify-content-start {
+ justify-content:flex-start!important
+}
+.justify-content-end {
+ justify-content:flex-end!important
+}
+.justify-content-center {
+ justify-content:center!important
+}
+.justify-content-between {
+ justify-content:space-between!important
+}
+.justify-content-around {
+ justify-content:space-around!important
+}
+.align-items-start {
+ align-items:flex-start!important
+}
+.align-items-end {
+ align-items:flex-end!important
+}
+.align-items-center {
+ align-items:center!important
+}
+.align-items-baseline {
+ align-items:baseline!important
+}
+.align-items-stretch {
+ align-items:stretch!important
+}
+.align-content-start {
+ align-content:flex-start!important
+}
+.align-content-end {
+ align-content:flex-end!important
+}
+.align-content-center {
+ align-content:center!important
+}
+.align-content-between {
+ align-content:space-between!important
+}
+.align-content-around {
+ align-content:space-around!important
+}
+.align-content-stretch {
+ align-content:stretch!important
+}
+.align-self-auto {
+ align-self:auto!important
+}
+.align-self-start {
+ align-self:flex-start!important
+}
+.align-self-end {
+ align-self:flex-end!important
+}
+.align-self-center {
+ align-self:center!important
+}
+.align-self-baseline {
+ align-self:baseline!important
+}
+.align-self-stretch {
+ align-self:stretch!important
+}
+@media (min-width:576px) {
+ .flex-sm-row {
+  flex-direction:row!important
+ }
+ .flex-sm-column {
+  flex-direction:column!important
+ }
+ .flex-sm-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-sm-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-sm-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-sm-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-sm-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-sm-fill {
+  flex:1 1 auto!important
+ }
+ .flex-sm-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-sm-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-sm-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-sm-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-sm-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-sm-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-sm-center {
+  justify-content:center!important
+ }
+ .justify-content-sm-between {
+  justify-content:space-between!important
+ }
+ .justify-content-sm-around {
+  justify-content:space-around!important
+ }
+ .align-items-sm-start {
+  align-items:flex-start!important
+ }
+ .align-items-sm-end {
+  align-items:flex-end!important
+ }
+ .align-items-sm-center {
+  align-items:center!important
+ }
+ .align-items-sm-baseline {
+  align-items:baseline!important
+ }
+ .align-items-sm-stretch {
+  align-items:stretch!important
+ }
+ .align-content-sm-start {
+  align-content:flex-start!important
+ }
+ .align-content-sm-end {
+  align-content:flex-end!important
+ }
+ .align-content-sm-center {
+  align-content:center!important
+ }
+ .align-content-sm-between {
+  align-content:space-between!important
+ }
+ .align-content-sm-around {
+  align-content:space-around!important
+ }
+ .align-content-sm-stretch {
+  align-content:stretch!important
+ }
+ .align-self-sm-auto {
+  align-self:auto!important
+ }
+ .align-self-sm-start {
+  align-self:flex-start!important
+ }
+ .align-self-sm-end {
+  align-self:flex-end!important
+ }
+ .align-self-sm-center {
+  align-self:center!important
+ }
+ .align-self-sm-baseline {
+  align-self:baseline!important
+ }
+ .align-self-sm-stretch {
+  align-self:stretch!important
+ }
+}
+@media (min-width:768px) {
+ .flex-md-row {
+  flex-direction:row!important
+ }
+ .flex-md-column {
+  flex-direction:column!important
+ }
+ .flex-md-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-md-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-md-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-md-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-md-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-md-fill {
+  flex:1 1 auto!important
+ }
+ .flex-md-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-md-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-md-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-md-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-md-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-md-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-md-center {
+  justify-content:center!important
+ }
+ .justify-content-md-between {
+  justify-content:space-between!important
+ }
+ .justify-content-md-around {
+  justify-content:space-around!important
+ }
+ .align-items-md-start {
+  align-items:flex-start!important
+ }
+ .align-items-md-end {
+  align-items:flex-end!important
+ }
+ .align-items-md-center {
+  align-items:center!important
+ }
+ .align-items-md-baseline {
+  align-items:baseline!important
+ }
+ .align-items-md-stretch {
+  align-items:stretch!important
+ }
+ .align-content-md-start {
+  align-content:flex-start!important
+ }
+ .align-content-md-end {
+  align-content:flex-end!important
+ }
+ .align-content-md-center {
+  align-content:center!important
+ }
+ .align-content-md-between {
+  align-content:space-between!important
+ }
+ .align-content-md-around {
+  align-content:space-around!important
+ }
+ .align-content-md-stretch {
+  align-content:stretch!important
+ }
+ .align-self-md-auto {
+  align-self:auto!important
+ }
+ .align-self-md-start {
+  align-self:flex-start!important
+ }
+ .align-self-md-end {
+  align-self:flex-end!important
+ }
+ .align-self-md-center {
+  align-self:center!important
+ }
+ .align-self-md-baseline {
+  align-self:baseline!important
+ }
+ .align-self-md-stretch {
+  align-self:stretch!important
+ }
+}
+@media (min-width:992px) {
+ .flex-lg-row {
+  flex-direction:row!important
+ }
+ .flex-lg-column {
+  flex-direction:column!important
+ }
+ .flex-lg-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-lg-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-lg-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-lg-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-lg-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-lg-fill {
+  flex:1 1 auto!important
+ }
+ .flex-lg-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-lg-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-lg-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-lg-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-lg-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-lg-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-lg-center {
+  justify-content:center!important
+ }
+ .justify-content-lg-between {
+  justify-content:space-between!important
+ }
+ .justify-content-lg-around {
+  justify-content:space-around!important
+ }
+ .align-items-lg-start {
+  align-items:flex-start!important
+ }
+ .align-items-lg-end {
+  align-items:flex-end!important
+ }
+ .align-items-lg-center {
+  align-items:center!important
+ }
+ .align-items-lg-baseline {
+  align-items:baseline!important
+ }
+ .align-items-lg-stretch {
+  align-items:stretch!important
+ }
+ .align-content-lg-start {
+  align-content:flex-start!important
+ }
+ .align-content-lg-end {
+  align-content:flex-end!important
+ }
+ .align-content-lg-center {
+  align-content:center!important
+ }
+ .align-content-lg-between {
+  align-content:space-between!important
+ }
+ .align-content-lg-around {
+  align-content:space-around!important
+ }
+ .align-content-lg-stretch {
+  align-content:stretch!important
+ }
+ .align-self-lg-auto {
+  align-self:auto!important
+ }
+ .align-self-lg-start {
+  align-self:flex-start!important
+ }
+ .align-self-lg-end {
+  align-self:flex-end!important
+ }
+ .align-self-lg-center {
+  align-self:center!important
+ }
+ .align-self-lg-baseline {
+  align-self:baseline!important
+ }
+ .align-self-lg-stretch {
+  align-self:stretch!important
+ }
+}
+@media (min-width:1200px) {
+ .flex-xl-row {
+  flex-direction:row!important
+ }
+ .flex-xl-column {
+  flex-direction:column!important
+ }
+ .flex-xl-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-xl-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-xl-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-xl-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-xl-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-xl-fill {
+  flex:1 1 auto!important
+ }
+ .flex-xl-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-xl-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-xl-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-xl-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-xl-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-xl-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-xl-center {
+  justify-content:center!important
+ }
+ .justify-content-xl-between {
+  justify-content:space-between!important
+ }
+ .justify-content-xl-around {
+  justify-content:space-around!important
+ }
+ .align-items-xl-start {
+  align-items:flex-start!important
+ }
+ .align-items-xl-end {
+  align-items:flex-end!important
+ }
+ .align-items-xl-center {
+  align-items:center!important
+ }
+ .align-items-xl-baseline {
+  align-items:baseline!important
+ }
+ .align-items-xl-stretch {
+  align-items:stretch!important
+ }
+ .align-content-xl-start {
+  align-content:flex-start!important
+ }
+ .align-content-xl-end {
+  align-content:flex-end!important
+ }
+ .align-content-xl-center {
+  align-content:center!important
+ }
+ .align-content-xl-between {
+  align-content:space-between!important
+ }
+ .align-content-xl-around {
+  align-content:space-around!important
+ }
+ .align-content-xl-stretch {
+  align-content:stretch!important
+ }
+ .align-self-xl-auto {
+  align-self:auto!important
+ }
+ .align-self-xl-start {
+  align-self:flex-start!important
+ }
+ .align-self-xl-end {
+  align-self:flex-end!important
+ }
+ .align-self-xl-center {
+  align-self:center!important
+ }
+ .align-self-xl-baseline {
+  align-self:baseline!important
+ }
+ .align-self-xl-stretch {
+  align-self:stretch!important
+ }
+}
+.float-left {
+ float:left!important
+}
+.float-right {
+ float:right!important
+}
+.float-none {
+ float:none!important
+}
+@media (min-width:576px) {
+ .float-sm-left {
+  float:left!important
+ }
+ .float-sm-right {
+  float:right!important
+ }
+ .float-sm-none {
+  float:none!important
+ }
+}
+@media (min-width:768px) {
+ .float-md-left {
+  float:left!important
+ }
+ .float-md-right {
+  float:right!important
+ }
+ .float-md-none {
+  float:none!important
+ }
+}
+@media (min-width:992px) {
+ .float-lg-left {
+  float:left!important
+ }
+ .float-lg-right {
+  float:right!important
+ }
+ .float-lg-none {
+  float:none!important
+ }
+}
+@media (min-width:1200px) {
+ .float-xl-left {
+  float:left!important
+ }
+ .float-xl-right {
+  float:right!important
+ }
+ .float-xl-none {
+  float:none!important
+ }
+}
+.user-select-all {
+ user-select:all!important
+}
+.user-select-auto {
+ user-select:auto!important
+}
+.user-select-none {
+ user-select:none!important
+}
+.overflow-auto {
+ overflow:auto!important
+}
+.overflow-hidden {
+ overflow:hidden!important
+}
+.position-static {
+ position:static!important
+}
+.position-relative {
+ position:relative!important
+}
+.position-absolute {
+ position:absolute!important
+}
+.position-fixed {
+ position:fixed!important
+}
+.position-sticky {
+ position:sticky!important
+}
+.fixed-top {
+ position:fixed;
+ top:0;
+ right:0;
+ left:0;
+ z-index:1030
+}
+.fixed-bottom {
+ position:fixed;
+ right:0;
+ bottom:0;
+ left:0;
+ z-index:1030
+}
+@supports (position:sticky) {
+ .sticky-top {
+  position:sticky;
+  top:0;
+  z-index:1020
+ }
+}
+.sr-only {
+ position:absolute;
+ width:1px;
+ height:1px;
+ padding:0;
+ margin:-1px;
+ overflow:hidden;
+ clip:rect(0,0,0,0);
+ white-space:nowrap;
+ border:0
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position:static;
+ width:auto;
+ height:auto;
+ overflow:visible;
+ clip:auto;
+ white-space:normal
+}
+.shadow-sm {
+ box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important
+}
+.shadow {
+ box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important
+}
+.shadow-lg {
+ box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important
+}
+.shadow-none {
+ box-shadow:none!important
+}
+.w-25 {
+ width:25%!important
+}
+.w-50 {
+ width:50%!important
+}
+.w-75 {
+ width:75%!important
+}
+.w-100 {
+ width:100%!important
+}
+.w-auto {
+ width:auto!important
+}
+.h-25 {
+ height:25%!important
+}
+.h-50 {
+ height:50%!important
+}
+.h-75 {
+ height:75%!important
+}
+.h-100 {
+ height:100%!important
+}
+.h-auto {
+ height:auto!important
+}
+.mw-100 {
+ max-width:100%!important
+}
+.mh-100 {
+ max-height:100%!important
+}
+.min-vw-100 {
+ min-width:100vw!important
+}
+.min-vh-100 {
+ min-height:100vh!important
+}
+.vw-100 {
+ width:100vw!important
+}
+.vh-100 {
+ height:100vh!important
+}
+.m-0 {
+ margin:0!important
+}
+.mt-0,
+.my-0 {
+ margin-top:0!important
+}
+.mr-0,
+.mx-0 {
+ margin-right:0!important
+}
+.mb-0,
+.my-0 {
+ margin-bottom:0!important
+}
+.ml-0,
+.mx-0 {
+ margin-left:0!important
+}
+.m-1 {
+ margin:.25rem!important
+}
+.mt-1,
+.my-1 {
+ margin-top:.25rem!important
+}
+.mr-1,
+.mx-1 {
+ margin-right:.25rem!important
+}
+.mb-1,
+.my-1 {
+ margin-bottom:.25rem!important
+}
+.ml-1,
+.mx-1 {
+ margin-left:.25rem!important
+}
+.m-2 {
+ margin:.5rem!important
+}
+.mt-2,
+.my-2 {
+ margin-top:.5rem!important
+}
+.mr-2,
+.mx-2 {
+ margin-right:.5rem!important
+}
+.mb-2,
+.my-2 {
+ margin-bottom:.5rem!important
+}
+.ml-2,
+.mx-2 {
+ margin-left:.5rem!important
+}
+.m-3 {
+ margin:1rem!important
+}
+.mt-3,
+.my-3 {
+ margin-top:1rem!important
+}
+.mr-3,
+.mx-3 {
+ margin-right:1rem!important
+}
+.mb-3,
+.my-3 {
+ margin-bottom:1rem!important
+}
+.ml-3,
+.mx-3 {
+ margin-left:1rem!important
+}
+.m-4 {
+ margin:1.5rem!important
+}
+.mt-4,
+.my-4 {
+ margin-top:1.5rem!important
+}
+.mr-4,
+.mx-4 {
+ margin-right:1.5rem!important
+}
+.mb-4,
+.my-4 {
+ margin-bottom:1.5rem!important
+}
+.ml-4,
+.mx-4 {
+ margin-left:1.5rem!important
+}
+.m-5 {
+ margin:3rem!important
+}
+.mt-5,
+.my-5 {
+ margin-top:3rem!important
+}
+.mr-5,
+.mx-5 {
+ margin-right:3rem!important
+}
+.mb-5,
+.my-5 {
+ margin-bottom:3rem!important
+}
+.ml-5,
+.mx-5 {
+ margin-left:3rem!important
+}
+.p-0 {
+ padding:0!important
+}
+.pt-0,
+.py-0 {
+ padding-top:0!important
+}
+.pr-0,
+.px-0 {
+ padding-right:0!important
+}
+.pb-0,
+.py-0 {
+ padding-bottom:0!important
+}
+.pl-0,
+.px-0 {
+ padding-left:0!important
+}
+.p-1 {
+ padding:.25rem!important
+}
+.pt-1,
+.py-1 {
+ padding-top:.25rem!important
+}
+.pr-1,
+.px-1 {
+ padding-right:.25rem!important
+}
+.pb-1,
+.py-1 {
+ padding-bottom:.25rem!important
+}
+.pl-1,
+.px-1 {
+ padding-left:.25rem!important
+}
+.p-2 {
+ padding:.5rem!important
+}
+.pt-2,
+.py-2 {
+ padding-top:.5rem!important
+}
+.pr-2,
+.px-2 {
+ padding-right:.5rem!important
+}
+.pb-2,
+.py-2 {
+ padding-bottom:.5rem!important
+}
+.pl-2,
+.px-2 {
+ padding-left:.5rem!important
+}
+.p-3 {
+ padding:1rem!important
+}
+.pt-3,
+.py-3 {
+ padding-top:1rem!important
+}
+.pr-3,
+.px-3 {
+ padding-right:1rem!important
+}
+.pb-3,
+.py-3 {
+ padding-bottom:1rem!important
+}
+.pl-3,
+.px-3 {
+ padding-left:1rem!important
+}
+.p-4 {
+ padding:1.5rem!important
+}
+.pt-4,
+.py-4 {
+ padding-top:1.5rem!important
+}
+.pr-4,
+.px-4 {
+ padding-right:1.5rem!important
+}
+.pb-4,
+.py-4 {
+ padding-bottom:1.5rem!important
+}
+.pl-4,
+.px-4 {
+ padding-left:1.5rem!important
+}
+.p-5 {
+ padding:3rem!important
+}
+.pt-5,
+.py-5 {
+ padding-top:3rem!important
+}
+.pr-5,
+.px-5 {
+ padding-right:3rem!important
+}
+.pb-5,
+.py-5 {
+ padding-bottom:3rem!important
+}
+.pl-5,
+.px-5 {
+ padding-left:3rem!important
+}
+.m-n1 {
+ margin:-.25rem!important
+}
+.mt-n1,
+.my-n1 {
+ margin-top:-.25rem!important
+}
+.mr-n1,
+.mx-n1 {
+ margin-right:-.25rem!important
+}
+.mb-n1,
+.my-n1 {
+ margin-bottom:-.25rem!important
+}
+.ml-n1,
+.mx-n1 {
+ margin-left:-.25rem!important
+}
+.m-n2 {
+ margin:-.5rem!important
+}
+.mt-n2,
+.my-n2 {
+ margin-top:-.5rem!important
+}
+.mr-n2,
+.mx-n2 {
+ margin-right:-.5rem!important
+}
+.mb-n2,
+.my-n2 {
+ margin-bottom:-.5rem!important
+}
+.ml-n2,
+.mx-n2 {
+ margin-left:-.5rem!important
+}
+.m-n3 {
+ margin:-1rem!important
+}
+.mt-n3,
+.my-n3 {
+ margin-top:-1rem!important
+}
+.mr-n3,
+.mx-n3 {
+ margin-right:-1rem!important
+}
+.mb-n3,
+.my-n3 {
+ margin-bottom:-1rem!important
+}
+.ml-n3,
+.mx-n3 {
+ margin-left:-1rem!important
+}
+.m-n4 {
+ margin:-1.5rem!important
+}
+.mt-n4,
+.my-n4 {
+ margin-top:-1.5rem!important
+}
+.mr-n4,
+.mx-n4 {
+ margin-right:-1.5rem!important
+}
+.mb-n4,
+.my-n4 {
+ margin-bottom:-1.5rem!important
+}
+.ml-n4,
+.mx-n4 {
+ margin-left:-1.5rem!important
+}
+.m-n5 {
+ margin:-3rem!important
+}
+.mt-n5,
+.my-n5 {
+ margin-top:-3rem!important
+}
+.mr-n5,
+.mx-n5 {
+ margin-right:-3rem!important
+}
+.mb-n5,
+.my-n5 {
+ margin-bottom:-3rem!important
+}
+.ml-n5,
+.mx-n5 {
+ margin-left:-3rem!important
+}
+.m-auto {
+ margin:auto!important
+}
+.mt-auto,
+.my-auto {
+ margin-top:auto!important
+}
+.mr-auto,
+.mx-auto {
+ margin-right:auto!important
+}
+.mb-auto,
+.my-auto {
+ margin-bottom:auto!important
+}
+.ml-auto,
+.mx-auto {
+ margin-left:auto!important
+}
+@media (min-width:576px) {
+ .m-sm-0 {
+  margin:0!important
+ }
+ .mt-sm-0,
+ .my-sm-0 {
+  margin-top:0!important
+ }
+ .mr-sm-0,
+ .mx-sm-0 {
+  margin-right:0!important
+ }
+ .mb-sm-0,
+ .my-sm-0 {
+  margin-bottom:0!important
+ }
+ .ml-sm-0,
+ .mx-sm-0 {
+  margin-left:0!important
+ }
+ .m-sm-1 {
+  margin:.25rem!important
+ }
+ .mt-sm-1,
+ .my-sm-1 {
+  margin-top:.25rem!important
+ }
+ .mr-sm-1,
+ .mx-sm-1 {
+  margin-right:.25rem!important
+ }
+ .mb-sm-1,
+ .my-sm-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-sm-1,
+ .mx-sm-1 {
+  margin-left:.25rem!important
+ }
+ .m-sm-2 {
+  margin:.5rem!important
+ }
+ .mt-sm-2,
+ .my-sm-2 {
+  margin-top:.5rem!important
+ }
+ .mr-sm-2,
+ .mx-sm-2 {
+  margin-right:.5rem!important
+ }
+ .mb-sm-2,
+ .my-sm-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-sm-2,
+ .mx-sm-2 {
+  margin-left:.5rem!important
+ }
+ .m-sm-3 {
+  margin:1rem!important
+ }
+ .mt-sm-3,
+ .my-sm-3 {
+  margin-top:1rem!important
+ }
+ .mr-sm-3,
+ .mx-sm-3 {
+  margin-right:1rem!important
+ }
+ .mb-sm-3,
+ .my-sm-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-sm-3,
+ .mx-sm-3 {
+  margin-left:1rem!important
+ }
+ .m-sm-4 {
+  margin:1.5rem!important
+ }
+ .mt-sm-4,
+ .my-sm-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-sm-4,
+ .mx-sm-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-sm-4,
+ .my-sm-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-sm-4,
+ .mx-sm-4 {
+  margin-left:1.5rem!important
+ }
+ .m-sm-5 {
+  margin:3rem!important
+ }
+ .mt-sm-5,
+ .my-sm-5 {
+  margin-top:3rem!important
+ }
+ .mr-sm-5,
+ .mx-sm-5 {
+  margin-right:3rem!important
+ }
+ .mb-sm-5,
+ .my-sm-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-sm-5,
+ .mx-sm-5 {
+  margin-left:3rem!important
+ }
+ .p-sm-0 {
+  padding:0!important
+ }
+ .pt-sm-0,
+ .py-sm-0 {
+  padding-top:0!important
+ }
+ .pr-sm-0,
+ .px-sm-0 {
+  padding-right:0!important
+ }
+ .pb-sm-0,
+ .py-sm-0 {
+  padding-bottom:0!important
+ }
+ .pl-sm-0,
+ .px-sm-0 {
+  padding-left:0!important
+ }
+ .p-sm-1 {
+  padding:.25rem!important
+ }
+ .pt-sm-1,
+ .py-sm-1 {
+  padding-top:.25rem!important
+ }
+ .pr-sm-1,
+ .px-sm-1 {
+  padding-right:.25rem!important
+ }
+ .pb-sm-1,
+ .py-sm-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-sm-1,
+ .px-sm-1 {
+  padding-left:.25rem!important
+ }
+ .p-sm-2 {
+  padding:.5rem!important
+ }
+ .pt-sm-2,
+ .py-sm-2 {
+  padding-top:.5rem!important
+ }
+ .pr-sm-2,
+ .px-sm-2 {
+  padding-right:.5rem!important
+ }
+ .pb-sm-2,
+ .py-sm-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-sm-2,
+ .px-sm-2 {
+  padding-left:.5rem!important
+ }
+ .p-sm-3 {
+  padding:1rem!important
+ }
+ .pt-sm-3,
+ .py-sm-3 {
+  padding-top:1rem!important
+ }
+ .pr-sm-3,
+ .px-sm-3 {
+  padding-right:1rem!important
+ }
+ .pb-sm-3,
+ .py-sm-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-sm-3,
+ .px-sm-3 {
+  padding-left:1rem!important
+ }
+ .p-sm-4 {
+  padding:1.5rem!important
+ }
+ .pt-sm-4,
+ .py-sm-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-sm-4,
+ .px-sm-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-sm-4,
+ .py-sm-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-sm-4,
+ .px-sm-4 {
+  padding-left:1.5rem!important
+ }
+ .p-sm-5 {
+  padding:3rem!important
+ }
+ .pt-sm-5,
+ .py-sm-5 {
+  padding-top:3rem!important
+ }
+ .pr-sm-5,
+ .px-sm-5 {
+  padding-right:3rem!important
+ }
+ .pb-sm-5,
+ .py-sm-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-sm-5,
+ .px-sm-5 {
+  padding-left:3rem!important
+ }
+ .m-sm-n1 {
+  margin:-.25rem!important
+ }
+ .mt-sm-n1,
+ .my-sm-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-sm-n1,
+ .mx-sm-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-sm-n1,
+ .my-sm-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-sm-n1,
+ .mx-sm-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-sm-n2 {
+  margin:-.5rem!important
+ }
+ .mt-sm-n2,
+ .my-sm-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-sm-n2,
+ .mx-sm-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-sm-n2,
+ .my-sm-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-sm-n2,
+ .mx-sm-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-sm-n3 {
+  margin:-1rem!important
+ }
+ .mt-sm-n3,
+ .my-sm-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-sm-n3,
+ .mx-sm-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-sm-n3,
+ .my-sm-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-sm-n3,
+ .mx-sm-n3 {
+  margin-left:-1rem!important
+ }
+ .m-sm-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-sm-n4,
+ .my-sm-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-sm-n4,
+ .mx-sm-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-sm-n4,
+ .my-sm-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-sm-n4,
+ .mx-sm-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-sm-n5 {
+  margin:-3rem!important
+ }
+ .mt-sm-n5,
+ .my-sm-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-sm-n5,
+ .mx-sm-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-sm-n5,
+ .my-sm-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-sm-n5,
+ .mx-sm-n5 {
+  margin-left:-3rem!important
+ }
+ .m-sm-auto {
+  margin:auto!important
+ }
+ .mt-sm-auto,
+ .my-sm-auto {
+  margin-top:auto!important
+ }
+ .mr-sm-auto,
+ .mx-sm-auto {
+  margin-right:auto!important
+ }
+ .mb-sm-auto,
+ .my-sm-auto {
+  margin-bottom:auto!important
+ }
+ .ml-sm-auto,
+ .mx-sm-auto {
+  margin-left:auto!important
+ }
+}
+@media (min-width:768px) {
+ .m-md-0 {
+  margin:0!important
+ }
+ .mt-md-0,
+ .my-md-0 {
+  margin-top:0!important
+ }
+ .mr-md-0,
+ .mx-md-0 {
+  margin-right:0!important
+ }
+ .mb-md-0,
+ .my-md-0 {
+  margin-bottom:0!important
+ }
+ .ml-md-0,
+ .mx-md-0 {
+  margin-left:0!important
+ }
+ .m-md-1 {
+  margin:.25rem!important
+ }
+ .mt-md-1,
+ .my-md-1 {
+  margin-top:.25rem!important
+ }
+ .mr-md-1,
+ .mx-md-1 {
+  margin-right:.25rem!important
+ }
+ .mb-md-1,
+ .my-md-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-md-1,
+ .mx-md-1 {
+  margin-left:.25rem!important
+ }
+ .m-md-2 {
+  margin:.5rem!important
+ }
+ .mt-md-2,
+ .my-md-2 {
+  margin-top:.5rem!important
+ }
+ .mr-md-2,
+ .mx-md-2 {
+  margin-right:.5rem!important
+ }
+ .mb-md-2,
+ .my-md-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-md-2,
+ .mx-md-2 {
+  margin-left:.5rem!important
+ }
+ .m-md-3 {
+  margin:1rem!important
+ }
+ .mt-md-3,
+ .my-md-3 {
+  margin-top:1rem!important
+ }
+ .mr-md-3,
+ .mx-md-3 {
+  margin-right:1rem!important
+ }
+ .mb-md-3,
+ .my-md-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-md-3,
+ .mx-md-3 {
+  margin-left:1rem!important
+ }
+ .m-md-4 {
+  margin:1.5rem!important
+ }
+ .mt-md-4,
+ .my-md-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-md-4,
+ .mx-md-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-md-4,
+ .my-md-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-md-4,
+ .mx-md-4 {
+  margin-left:1.5rem!important
+ }
+ .m-md-5 {
+  margin:3rem!important
+ }
+ .mt-md-5,
+ .my-md-5 {
+  margin-top:3rem!important
+ }
+ .mr-md-5,
+ .mx-md-5 {
+  margin-right:3rem!important
+ }
+ .mb-md-5,
+ .my-md-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-md-5,
+ .mx-md-5 {
+  margin-left:3rem!important
+ }
+ .p-md-0 {
+  padding:0!important
+ }
+ .pt-md-0,
+ .py-md-0 {
+  padding-top:0!important
+ }
+ .pr-md-0,
+ .px-md-0 {
+  padding-right:0!important
+ }
+ .pb-md-0,
+ .py-md-0 {
+  padding-bottom:0!important
+ }
+ .pl-md-0,
+ .px-md-0 {
+  padding-left:0!important
+ }
+ .p-md-1 {
+  padding:.25rem!important
+ }
+ .pt-md-1,
+ .py-md-1 {
+  padding-top:.25rem!important
+ }
+ .pr-md-1,
+ .px-md-1 {
+  padding-right:.25rem!important
+ }
+ .pb-md-1,
+ .py-md-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-md-1,
+ .px-md-1 {
+  padding-left:.25rem!important
+ }
+ .p-md-2 {
+  padding:.5rem!important
+ }
+ .pt-md-2,
+ .py-md-2 {
+  padding-top:.5rem!important
+ }
+ .pr-md-2,
+ .px-md-2 {
+  padding-right:.5rem!important
+ }
+ .pb-md-2,
+ .py-md-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-md-2,
+ .px-md-2 {
+  padding-left:.5rem!important
+ }
+ .p-md-3 {
+  padding:1rem!important
+ }
+ .pt-md-3,
+ .py-md-3 {
+  padding-top:1rem!important
+ }
+ .pr-md-3,
+ .px-md-3 {
+  padding-right:1rem!important
+ }
+ .pb-md-3,
+ .py-md-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-md-3,
+ .px-md-3 {
+  padding-left:1rem!important
+ }
+ .p-md-4 {
+  padding:1.5rem!important
+ }
+ .pt-md-4,
+ .py-md-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-md-4,
+ .px-md-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-md-4,
+ .py-md-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-md-4,
+ .px-md-4 {
+  padding-left:1.5rem!important
+ }
+ .p-md-5 {
+  padding:3rem!important
+ }
+ .pt-md-5,
+ .py-md-5 {
+  padding-top:3rem!important
+ }
+ .pr-md-5,
+ .px-md-5 {
+  padding-right:3rem!important
+ }
+ .pb-md-5,
+ .py-md-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-md-5,
+ .px-md-5 {
+  padding-left:3rem!important
+ }
+ .m-md-n1 {
+  margin:-.25rem!important
+ }
+ .mt-md-n1,
+ .my-md-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-md-n1,
+ .mx-md-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-md-n1,
+ .my-md-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-md-n1,
+ .mx-md-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-md-n2 {
+  margin:-.5rem!important
+ }
+ .mt-md-n2,
+ .my-md-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-md-n2,
+ .mx-md-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-md-n2,
+ .my-md-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-md-n2,
+ .mx-md-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-md-n3 {
+  margin:-1rem!important
+ }
+ .mt-md-n3,
+ .my-md-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-md-n3,
+ .mx-md-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-md-n3,
+ .my-md-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-md-n3,
+ .mx-md-n3 {
+  margin-left:-1rem!important
+ }
+ .m-md-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-md-n4,
+ .my-md-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-md-n4,
+ .mx-md-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-md-n4,
+ .my-md-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-md-n4,
+ .mx-md-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-md-n5 {
+  margin:-3rem!important
+ }
+ .mt-md-n5,
+ .my-md-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-md-n5,
+ .mx-md-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-md-n5,
+ .my-md-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-md-n5,
+ .mx-md-n5 {
+  margin-left:-3rem!important
+ }
+ .m-md-auto {
+  margin:auto!important
+ }
+ .mt-md-auto,
+ .my-md-auto {
+  margin-top:auto!important
+ }
+ .mr-md-auto,
+ .mx-md-auto {
+  margin-right:auto!important
+ }
+ .mb-md-auto,
+ .my-md-auto {
+  margin-bottom:auto!important
+ }
+ .ml-md-auto,
+ .mx-md-auto {
+  margin-left:auto!important
+ }
+}
+@media (min-width:992px) {
+ .m-lg-0 {
+  margin:0!important
+ }
+ .mt-lg-0,
+ .my-lg-0 {
+  margin-top:0!important
+ }
+ .mr-lg-0,
+ .mx-lg-0 {
+  margin-right:0!important
+ }
+ .mb-lg-0,
+ .my-lg-0 {
+  margin-bottom:0!important
+ }
+ .ml-lg-0,
+ .mx-lg-0 {
+  margin-left:0!important
+ }
+ .m-lg-1 {
+  margin:.25rem!important
+ }
+ .mt-lg-1,
+ .my-lg-1 {
+  margin-top:.25rem!important
+ }
+ .mr-lg-1,
+ .mx-lg-1 {
+  margin-right:.25rem!important
+ }
+ .mb-lg-1,
+ .my-lg-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-lg-1,
+ .mx-lg-1 {
+  margin-left:.25rem!important
+ }
+ .m-lg-2 {
+  margin:.5rem!important
+ }
+ .mt-lg-2,
+ .my-lg-2 {
+  margin-top:.5rem!important
+ }
+ .mr-lg-2,
+ .mx-lg-2 {
+  margin-right:.5rem!important
+ }
+ .mb-lg-2,
+ .my-lg-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-lg-2,
+ .mx-lg-2 {
+  margin-left:.5rem!important
+ }
+ .m-lg-3 {
+  margin:1rem!important
+ }
+ .mt-lg-3,
+ .my-lg-3 {
+  margin-top:1rem!important
+ }
+ .mr-lg-3,
+ .mx-lg-3 {
+  margin-right:1rem!important
+ }
+ .mb-lg-3,
+ .my-lg-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-lg-3,
+ .mx-lg-3 {
+  margin-left:1rem!important
+ }
+ .m-lg-4 {
+  margin:1.5rem!important
+ }
+ .mt-lg-4,
+ .my-lg-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-lg-4,
+ .mx-lg-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-lg-4,
+ .my-lg-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-lg-4,
+ .mx-lg-4 {
+  margin-left:1.5rem!important
+ }
+ .m-lg-5 {
+  margin:3rem!important
+ }
+ .mt-lg-5,
+ .my-lg-5 {
+  margin-top:3rem!important
+ }
+ .mr-lg-5,
+ .mx-lg-5 {
+  margin-right:3rem!important
+ }
+ .mb-lg-5,
+ .my-lg-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-lg-5,
+ .mx-lg-5 {
+  margin-left:3rem!important
+ }
+ .p-lg-0 {
+  padding:0!important
+ }
+ .pt-lg-0,
+ .py-lg-0 {
+  padding-top:0!important
+ }
+ .pr-lg-0,
+ .px-lg-0 {
+  padding-right:0!important
+ }
+ .pb-lg-0,
+ .py-lg-0 {
+  padding-bottom:0!important
+ }
+ .pl-lg-0,
+ .px-lg-0 {
+  padding-left:0!important
+ }
+ .p-lg-1 {
+  padding:.25rem!important
+ }
+ .pt-lg-1,
+ .py-lg-1 {
+  padding-top:.25rem!important
+ }
+ .pr-lg-1,
+ .px-lg-1 {
+  padding-right:.25rem!important
+ }
+ .pb-lg-1,
+ .py-lg-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-lg-1,
+ .px-lg-1 {
+  padding-left:.25rem!important
+ }
+ .p-lg-2 {
+  padding:.5rem!important
+ }
+ .pt-lg-2,
+ .py-lg-2 {
+  padding-top:.5rem!important
+ }
+ .pr-lg-2,
+ .px-lg-2 {
+  padding-right:.5rem!important
+ }
+ .pb-lg-2,
+ .py-lg-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-lg-2,
+ .px-lg-2 {
+  padding-left:.5rem!important
+ }
+ .p-lg-3 {
+  padding:1rem!important
+ }
+ .pt-lg-3,
+ .py-lg-3 {
+  padding-top:1rem!important
+ }
+ .pr-lg-3,
+ .px-lg-3 {
+  padding-right:1rem!important
+ }
+ .pb-lg-3,
+ .py-lg-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-lg-3,
+ .px-lg-3 {
+  padding-left:1rem!important
+ }
+ .p-lg-4 {
+  padding:1.5rem!important
+ }
+ .pt-lg-4,
+ .py-lg-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-lg-4,
+ .px-lg-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-lg-4,
+ .py-lg-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-lg-4,
+ .px-lg-4 {
+  padding-left:1.5rem!important
+ }
+ .p-lg-5 {
+  padding:3rem!important
+ }
+ .pt-lg-5,
+ .py-lg-5 {
+  padding-top:3rem!important
+ }
+ .pr-lg-5,
+ .px-lg-5 {
+  padding-right:3rem!important
+ }
+ .pb-lg-5,
+ .py-lg-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-lg-5,
+ .px-lg-5 {
+  padding-left:3rem!important
+ }
+ .m-lg-n1 {
+  margin:-.25rem!important
+ }
+ .mt-lg-n1,
+ .my-lg-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-lg-n1,
+ .mx-lg-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-lg-n1,
+ .my-lg-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-lg-n1,
+ .mx-lg-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-lg-n2 {
+  margin:-.5rem!important
+ }
+ .mt-lg-n2,
+ .my-lg-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-lg-n2,
+ .mx-lg-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-lg-n2,
+ .my-lg-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-lg-n2,
+ .mx-lg-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-lg-n3 {
+  margin:-1rem!important
+ }
+ .mt-lg-n3,
+ .my-lg-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-lg-n3,
+ .mx-lg-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-lg-n3,
+ .my-lg-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-lg-n3,
+ .mx-lg-n3 {
+  margin-left:-1rem!important
+ }
+ .m-lg-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-lg-n4,
+ .my-lg-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-lg-n4,
+ .mx-lg-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-lg-n4,
+ .my-lg-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-lg-n4,
+ .mx-lg-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-lg-n5 {
+  margin:-3rem!important
+ }
+ .mt-lg-n5,
+ .my-lg-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-lg-n5,
+ .mx-lg-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-lg-n5,
+ .my-lg-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-lg-n5,
+ .mx-lg-n5 {
+  margin-left:-3rem!important
+ }
+ .m-lg-auto {
+  margin:auto!important
+ }
+ .mt-lg-auto,
+ .my-lg-auto {
+  margin-top:auto!important
+ }
+ .mr-lg-auto,
+ .mx-lg-auto {
+  margin-right:auto!important
+ }
+ .mb-lg-auto,
+ .my-lg-auto {
+  margin-bottom:auto!important
+ }
+ .ml-lg-auto,
+ .mx-lg-auto {
+  margin-left:auto!important
+ }
+}
+@media (min-width:1200px) {
+ .m-xl-0 {
+  margin:0!important
+ }
+ .mt-xl-0,
+ .my-xl-0 {
+  margin-top:0!important
+ }
+ .mr-xl-0,
+ .mx-xl-0 {
+  margin-right:0!important
+ }
+ .mb-xl-0,
+ .my-xl-0 {
+  margin-bottom:0!important
+ }
+ .ml-xl-0,
+ .mx-xl-0 {
+  margin-left:0!important
+ }
+ .m-xl-1 {
+  margin:.25rem!important
+ }
+ .mt-xl-1,
+ .my-xl-1 {
+  margin-top:.25rem!important
+ }
+ .mr-xl-1,
+ .mx-xl-1 {
+  margin-right:.25rem!important
+ }
+ .mb-xl-1,
+ .my-xl-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-xl-1,
+ .mx-xl-1 {
+  margin-left:.25rem!important
+ }
+ .m-xl-2 {
+  margin:.5rem!important
+ }
+ .mt-xl-2,
+ .my-xl-2 {
+  margin-top:.5rem!important
+ }
+ .mr-xl-2,
+ .mx-xl-2 {
+  margin-right:.5rem!important
+ }
+ .mb-xl-2,
+ .my-xl-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-xl-2,
+ .mx-xl-2 {
+  margin-left:.5rem!important
+ }
+ .m-xl-3 {
+  margin:1rem!important
+ }
+ .mt-xl-3,
+ .my-xl-3 {
+  margin-top:1rem!important
+ }
+ .mr-xl-3,
+ .mx-xl-3 {
+  margin-right:1rem!important
+ }
+ .mb-xl-3,
+ .my-xl-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-xl-3,
+ .mx-xl-3 {
+  margin-left:1rem!important
+ }
+ .m-xl-4 {
+  margin:1.5rem!important
+ }
+ .mt-xl-4,
+ .my-xl-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-xl-4,
+ .mx-xl-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-xl-4,
+ .my-xl-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-xl-4,
+ .mx-xl-4 {
+  margin-left:1.5rem!important
+ }
+ .m-xl-5 {
+  margin:3rem!important
+ }
+ .mt-xl-5,
+ .my-xl-5 {
+  margin-top:3rem!important
+ }
+ .mr-xl-5,
+ .mx-xl-5 {
+  margin-right:3rem!important
+ }
+ .mb-xl-5,
+ .my-xl-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-xl-5,
+ .mx-xl-5 {
+  margin-left:3rem!important
+ }
+ .p-xl-0 {
+  padding:0!important
+ }
+ .pt-xl-0,
+ .py-xl-0 {
+  padding-top:0!important
+ }
+ .pr-xl-0,
+ .px-xl-0 {
+  padding-right:0!important
+ }
+ .pb-xl-0,
+ .py-xl-0 {
+  padding-bottom:0!important
+ }
+ .pl-xl-0,
+ .px-xl-0 {
+  padding-left:0!important
+ }
+ .p-xl-1 {
+  padding:.25rem!important
+ }
+ .pt-xl-1,
+ .py-xl-1 {
+  padding-top:.25rem!important
+ }
+ .pr-xl-1,
+ .px-xl-1 {
+  padding-right:.25rem!important
+ }
+ .pb-xl-1,
+ .py-xl-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-xl-1,
+ .px-xl-1 {
+  padding-left:.25rem!important
+ }
+ .p-xl-2 {
+  padding:.5rem!important
+ }
+ .pt-xl-2,
+ .py-xl-2 {
+  padding-top:.5rem!important
+ }
+ .pr-xl-2,
+ .px-xl-2 {
+  padding-right:.5rem!important
+ }
+ .pb-xl-2,
+ .py-xl-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-xl-2,
+ .px-xl-2 {
+  padding-left:.5rem!important
+ }
+ .p-xl-3 {
+  padding:1rem!important
+ }
+ .pt-xl-3,
+ .py-xl-3 {
+  padding-top:1rem!important
+ }
+ .pr-xl-3,
+ .px-xl-3 {
+  padding-right:1rem!important
+ }
+ .pb-xl-3,
+ .py-xl-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-xl-3,
+ .px-xl-3 {
+  padding-left:1rem!important
+ }
+ .p-xl-4 {
+  padding:1.5rem!important
+ }
+ .pt-xl-4,
+ .py-xl-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-xl-4,
+ .px-xl-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-xl-4,
+ .py-xl-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-xl-4,
+ .px-xl-4 {
+  padding-left:1.5rem!important
+ }
+ .p-xl-5 {
+  padding:3rem!important
+ }
+ .pt-xl-5,
+ .py-xl-5 {
+  padding-top:3rem!important
+ }
+ .pr-xl-5,
+ .px-xl-5 {
+  padding-right:3rem!important
+ }
+ .pb-xl-5,
+ .py-xl-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-xl-5,
+ .px-xl-5 {
+  padding-left:3rem!important
+ }
+ .m-xl-n1 {
+  margin:-.25rem!important
+ }
+ .mt-xl-n1,
+ .my-xl-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-xl-n1,
+ .mx-xl-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-xl-n1,
+ .my-xl-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-xl-n1,
+ .mx-xl-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-xl-n2 {
+  margin:-.5rem!important
+ }
+ .mt-xl-n2,
+ .my-xl-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-xl-n2,
+ .mx-xl-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-xl-n2,
+ .my-xl-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-xl-n2,
+ .mx-xl-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-xl-n3 {
+  margin:-1rem!important
+ }
+ .mt-xl-n3,
+ .my-xl-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-xl-n3,
+ .mx-xl-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-xl-n3,
+ .my-xl-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-xl-n3,
+ .mx-xl-n3 {
+  margin-left:-1rem!important
+ }
+ .m-xl-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-xl-n4,
+ .my-xl-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-xl-n4,
+ .mx-xl-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-xl-n4,
+ .my-xl-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-xl-n4,
+ .mx-xl-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-xl-n5 {
+  margin:-3rem!important
+ }
+ .mt-xl-n5,
+ .my-xl-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-xl-n5,
+ .mx-xl-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-xl-n5,
+ .my-xl-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-xl-n5,
+ .mx-xl-n5 {
+  margin-left:-3rem!important
+ }
+ .m-xl-auto {
+  margin:auto!important
+ }
+ .mt-xl-auto,
+ .my-xl-auto {
+  margin-top:auto!important
+ }
+ .mr-xl-auto,
+ .mx-xl-auto {
+  margin-right:auto!important
+ }
+ .mb-xl-auto,
+ .my-xl-auto {
+  margin-bottom:auto!important
+ }
+ .ml-xl-auto,
+ .mx-xl-auto {
+  margin-left:auto!important
+ }
+}
+.stretched-link::after {
+ position:absolute;
+ top:0;
+ right:0;
+ bottom:0;
+ left:0;
+ z-index:1;
+ pointer-events:auto;
+ content:"";
+ background-color:rgba(0,0,0,0)
+}
+.text-monospace {
+ font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important
+}
+.text-justify {
+ text-align:justify!important
+}
+.text-wrap {
+ white-space:normal!important
+}
+.text-nowrap {
+ white-space:nowrap!important
+}
+.text-truncate {
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap
+}
+.text-left {
+ text-align:left!important
+}
+.text-right {
+ text-align:right!important
+}
+.text-center {
+ text-align:center!important
+}
+@media (min-width:576px) {
+ .text-sm-left {
+  text-align:left!important
+ }
+ .text-sm-right {
+  text-align:right!important
+ }
+ .text-sm-center {
+  text-align:center!important
+ }
+}
+@media (min-width:768px) {
+ .text-md-left {
+  text-align:left!important
+ }
+ .text-md-right {
+  text-align:right!important
+ }
+ .text-md-center {
+  text-align:center!important
+ }
+}
+@media (min-width:992px) {
+ .text-lg-left {
+  text-align:left!important
+ }
+ .text-lg-right {
+  text-align:right!important
+ }
+ .text-lg-center {
+  text-align:center!important
+ }
+}
+@media (min-width:1200px) {
+ .text-xl-left {
+  text-align:left!important
+ }
+ .text-xl-right {
+  text-align:right!important
+ }
+ .text-xl-center {
+  text-align:center!important
+ }
+}
+.text-lowercase {
+ text-transform:lowercase!important
+}
+.text-uppercase {
+ text-transform:uppercase!important
+}
+.text-capitalize {
+ text-transform:capitalize!important
+}
+.font-weight-light {
+ font-weight:300!important
+}
+.font-weight-lighter {
+ font-weight:lighter!important
+}
+.font-weight-normal {
+ font-weight:400!important
+}
+.font-weight-bold {
+ font-weight:700!important
+}
+.font-weight-bolder {
+ font-weight:bolder!important
+}
+.font-italic {
+ font-style:italic!important
+}
+.text-white {
+ color:#fff!important
+}
+.text-primary {
+ color:#375a7f!important
+}
+a.text-primary:focus,
+a.text-primary:hover {
+ color:#20344a!important
+}
+.text-secondary {
+ color:#444!important
+}
+a.text-secondary:focus,
+a.text-secondary:hover {
+ color:#1e1e1e!important
+}
+.text-success {
+ color:#00bc8c!important
+}
+a.text-success:focus,
+a.text-success:hover {
+ color:#007053!important
+}
+.text-info {
+ color:#3498db!important
+}
+a.text-info:focus,
+a.text-info:hover {
+ color:#1d6fa5!important
+}
+.text-warning {
+ color:#f39c12!important
+}
+a.text-warning:focus,
+a.text-warning:hover {
+ color:#b06f09!important
+}
+.text-danger {
+ color:#e74c3c!important
+}
+a.text-danger:focus,
+a.text-danger:hover {
+ color:#bf2718!important
+}
+.text-light {
+ color:#303030!important
+}
+a.text-light:focus,
+a.text-light:hover {
+ color:#0a0a0a!important
+}
+.text-dark {
+ color:#dee2e6!important
+}
+a.text-dark:focus,
+a.text-dark:hover {
+ color:#b2bcc5!important
+}
+.text-body {
+ color:#dee2e6!important
+}
+.text-muted {
+ color:#888!important
+}
+.text-black-50 {
+ color:rgba(0,0,0,.5)!important
+}
+.text-white-50 {
+ color:rgba(255,255,255,.5)!important
+}
+.text-hide {
+ font:0/0 a;
+ color:transparent;
+ text-shadow:none;
+ background-color:transparent;
+ border:0
+}
+.text-decoration-none {
+ text-decoration:none!important
+}
+.text-break {
+ word-wrap:break-word!important
+}
+.text-reset {
+ color:inherit!important
+}
+.visible {
+ visibility:visible!important
+}
+.invisible {
+ visibility:hidden!important
+}
+@media print {
+ *,
+ ::after,
+ ::before {
+  text-shadow:none!important;
+  box-shadow:none!important
+ }
+ a:not(.btn) {
+  text-decoration:underline
+ }
+ abbr[title]::after {
+  content:" (" attr(title) ")"
+ }
+ pre {
+  white-space:pre-wrap!important
+ }
+ blockquote,
+ pre {
+  border:1px solid #adb5bd;
+  page-break-inside:avoid
+ }
+ thead {
+  display:table-header-group
+ }
+ img,
+ tr {
+  page-break-inside:avoid
+ }
+ h2,
+ h3,
+ p {
+  orphans:3;
+  widows:3
+ }
+ h2,
+ h3 {
+  page-break-after:avoid
+ }
+ @page {
+  size:a3
+ }
+ body {
+  min-width:992px!important
+ }
+ .container {
+  min-width:992px!important
+ }
+ .navbar {
+  display:none
+ }
+ .badge {
+  border:1px solid #000
+ }
+ .table {
+  border-collapse:collapse!important
+ }
+ .table td,
+ .table th {
+  background-color:#fff!important
+ }
+ .table-bordered td,
+ .table-bordered th {
+  border:1px solid #dee2e6!important
+ }
+ .table-dark {
+  color:inherit
+ }
+ .table-dark tbody+tbody,
+ .table-dark td,
+ .table-dark th,
+ .table-dark thead th {
+  border-color:#444
+ }
+ .table .thead-dark th {
+  color:inherit;
+  border-color:#444
+ }
+}
diff --git a/src/assets/css/themes/darkly.css b/src/assets/css/themes/darkly.css
new file mode 100644 (file)
index 0000000..bb4e355
--- /dev/null
@@ -0,0 +1 @@
+:root{--blue:#375a7f;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#e74c3c;--orange:#fd7e14;--yellow:#f39c12;--green:#00bc8c;--teal:#20c997;--cyan:#3498db;--white:#fff;--gray:#888;--gray-dark:#303030;--primary:#375a7f;--secondary:#444;--success:#00bc8c;--info:#3498db;--warning:#f39c12;--danger:#e74c3c;--light:#303030;--dark:#dee2e6;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:"Lato",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Cantarell,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:.9375rem;font-weight:400;line-height:1.5;color:#dee2e6;text-align:left;background-color:#222}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#00bc8c;text-decoration:none;background-color:transparent}a:hover{color:#007053;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#888;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:3rem}.h2,h2{font-size:2.5rem}.h3,h3{font-size:2rem}.h4,h4{font-size:1.40625rem}.h5,h5{font-size:1.17188rem}.h6,h6{font-size:.9375rem}.lead{font-size:1.17188rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#333}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.17188rem}.blockquote-footer{display:block;font-size:80%;color:#888}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#222;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#888}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#222;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:inherit}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-auto{flex:0 0 auto;width:auto;max-width:100%}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-md-auto{flex:0 0 auto;width:auto;max-width:100%}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;margin-bottom:1rem;color:#dee2e6}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #444}.table thead th{vertical-align:bottom;border-bottom:2px solid #444}.table tbody+tbody{border-top:2px solid #444}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #444}.table-bordered td,.table-bordered th{border:1px solid #444}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:#303030}.table-hover tbody tr:hover{color:#dee2e6;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#c7d1db}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#97a9bc}.table-hover .table-primary:hover{background-color:#b7c4d1}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#b7c4d1}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#cbcbcb}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#9e9e9e}.table-hover .table-secondary:hover{background-color:#bebebe}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#bebebe}.table-success,.table-success>td,.table-success>th{background-color:#b8ecdf}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#7adcc3}.table-hover .table-success:hover{background-color:#a4e7d6}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#a4e7d6}.table-info,.table-info>td,.table-info>th{background-color:#c6e2f5}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#95c9ec}.table-hover .table-info:hover{background-color:#b0d7f1}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#b0d7f1}.table-warning,.table-warning>td,.table-warning>th{background-color:#fce3bd}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#f9cc84}.table-hover .table-warning:hover{background-color:#fbd9a5}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#fbd9a5}.table-danger,.table-danger>td,.table-danger>th{background-color:#f8cdc8}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#f3a29a}.table-hover .table-danger:hover{background-color:#f5b8b1}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f5b8b1}.table-light,.table-light>td,.table-light>th{background-color:#c5c5c5}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#939393}.table-hover .table-light:hover{background-color:#b8b8b8}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#b8b8b8}.table-dark,.table-dark>td,.table-dark>th{background-color:#f6f7f8}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#eef0f2}.table-hover .table-dark:hover{background-color:#e8eaed}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#e8eaed}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#303030;border-color:#434343}.table .thead-light th{color:#444;background-color:#ebebeb;border-color:#444}.table-dark{color:#fff;background-color:#303030}.table-dark td,.table-dark th,.table-dark thead th{border-color:#434343}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:.9375rem;font-weight:400;line-height:1.5;color:#fff;background-color:#444;background-clip:padding-box;border:1px solid #222;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #fff}.form-control:focus{color:#fff;background-color:#444;border-color:#739ac2;outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.form-control::placeholder{color:#888;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#2b2b2b;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{appearance:none}select.form-control:focus::-ms-value{color:#fff;background-color:#444}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.17188rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.82031rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:.9375rem;line-height:1.5;color:#dee2e6;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.82031rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.17188rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#888}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#00bc8c}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.82031rem;line-height:1.5;color:#fff;background-color:rgba(0,188,140,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#00bc8c;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2300bc8c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#00bc8c;box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#00bc8c;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2300bc8c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #444 no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#00bc8c;box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#00bc8c}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#00bc8c}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#00bc8c}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#00efb2;background-color:#00efb2}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#00bc8c}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#00bc8c}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#00bc8c;box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#e74c3c}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.82031rem;line-height:1.5;color:#fff;background-color:rgba(231,76,60,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#e74c3c;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23e74c3c' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e74c3c' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#e74c3c;box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#e74c3c;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23e74c3c' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e74c3c' stroke='none'/%3e%3c/svg%3e") #444 no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#e74c3c;box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#e74c3c}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#e74c3c}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#e74c3c}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#ed7669;background-color:#ed7669}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#e74c3c}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#e74c3c}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#e74c3c;box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#dee2e6;text-align:center;vertical-align:middle;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:.9375rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#dee2e6;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-primary:hover{color:#fff;background-color:#2b4764;border-color:#28415b}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#2b4764;border-color:#28415b;box-shadow:0 0 0 .2rem rgba(85,115,146,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#28415b;border-color:#243a53}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(85,115,146,.5)}.btn-secondary{color:#fff;background-color:#444;border-color:#444}.btn-secondary:hover{color:#fff;background-color:#313131;border-color:#2b2b2b}.btn-secondary.focus,.btn-secondary:focus{color:#fff;background-color:#313131;border-color:#2b2b2b;box-shadow:0 0 0 .2rem rgba(96,96,96,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#444;border-color:#444}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#2b2b2b;border-color:#242424}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(96,96,96,.5)}.btn-success{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-success:hover{color:#fff;background-color:#009670;border-color:#008966}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#009670;border-color:#008966;box-shadow:0 0 0 .2rem rgba(38,198,157,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#008966;border-color:#007c5d}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,198,157,.5)}.btn-info{color:#fff;background-color:#3498db;border-color:#3498db}.btn-info:hover{color:#fff;background-color:#2384c6;border-color:#217dbb}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#2384c6;border-color:#217dbb;box-shadow:0 0 0 .2rem rgba(82,167,224,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#3498db;border-color:#3498db}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#217dbb;border-color:#1f76b0}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,167,224,.5)}.btn-warning{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-warning:hover{color:#fff;background-color:#d4860b;border-color:#c87f0a}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#d4860b;border-color:#c87f0a;box-shadow:0 0 0 .2rem rgba(245,171,54,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#c87f0a;border-color:#bc770a}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(245,171,54,.5)}.btn-danger{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:hover{color:#fff;background-color:#e12e1c;border-color:#d62c1a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#e12e1c;border-color:#d62c1a;box-shadow:0 0 0 .2rem rgba(235,103,89,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#d62c1a;border-color:#ca2a19}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(235,103,89,.5)}.btn-light{color:#fff;background-color:#303030;border-color:#303030}.btn-light:hover{color:#fff;background-color:#1d1d1d;border-color:#171717}.btn-light.focus,.btn-light:focus{color:#fff;background-color:#1d1d1d;border-color:#171717;box-shadow:0 0 0 .2rem rgba(79,79,79,.5)}.btn-light.disabled,.btn-light:disabled{color:#fff;background-color:#303030;border-color:#303030}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#fff;background-color:#171717;border-color:#101010}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(79,79,79,.5)}.btn-dark{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-dark:hover{color:#222;background-color:#c8cfd6;border-color:#c1c9d0}.btn-dark.focus,.btn-dark:focus{color:#222;background-color:#c8cfd6;border-color:#c1c9d0;box-shadow:0 0 0 .2rem rgba(194,197,201,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#222;background-color:#c1c9d0;border-color:#bac2cb}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(194,197,201,.5)}.btn-outline-primary{color:#375a7f;border-color:#375a7f}.btn-outline-primary:hover{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(55,90,127,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#375a7f;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(55,90,127,.5)}.btn-outline-secondary{color:#444;border-color:#444}.btn-outline-secondary:hover{color:#fff;background-color:#444;border-color:#444}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(68,68,68,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#444;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#444;border-color:#444}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(68,68,68,.5)}.btn-outline-success{color:#00bc8c;border-color:#00bc8c}.btn-outline-success:hover{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(0,188,140,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#00bc8c;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,188,140,.5)}.btn-outline-info{color:#3498db;border-color:#3498db}.btn-outline-info:hover{color:#fff;background-color:#3498db;border-color:#3498db}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(52,152,219,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#3498db;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#3498db;border-color:#3498db}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,152,219,.5)}.btn-outline-warning{color:#f39c12;border-color:#f39c12}.btn-outline-warning:hover{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(243,156,18,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#f39c12;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(243,156,18,.5)}.btn-outline-danger{color:#e74c3c;border-color:#e74c3c}.btn-outline-danger:hover{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(231,76,60,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#e74c3c;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(231,76,60,.5)}.btn-outline-light{color:#303030;border-color:#303030}.btn-outline-light:hover{color:#fff;background-color:#303030;border-color:#303030}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(48,48,48,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#303030;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#303030;border-color:#303030}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(48,48,48,.5)}.btn-outline-dark{color:#dee2e6;border-color:#dee2e6}.btn-outline-dark:hover{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(222,226,230,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#dee2e6;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,226,230,.5)}.btn-link{font-weight:400;color:#00bc8c;text-decoration:none}.btn-link:hover{color:#007053;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#888;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.17188rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.82031rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:.9375rem;color:#dee2e6;text-align:left;list-style:none;background-color:#222;background-clip:padding-box;border:1px solid #444;border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #444}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#fff;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#fff;text-decoration:none;background-color:#375a7f}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#375a7f}.dropdown-item.disabled,.dropdown-item:disabled{color:#888;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.82031rem;color:#888;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:flex;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:.9375rem;font-weight:400;line-height:1.5;color:#adb5bd;text-align:center;white-space:nowrap;background-color:#444;border:1px solid #222;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.17188rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.82031rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.40625rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.20312rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#375a7f;background-color:#375a7f}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#739ac2}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#97b3d2;border-color:#97b3d2}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#888}.custom-control-input:disabled~.custom-control-label::before,.custom-control-input[disabled]~.custom-control-label::before{background-color:#2b2b2b}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.20312rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#444;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.20312rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#375a7f;background-color:#375a7f}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.20312rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#444;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:.9375rem;font-weight:400;line-height:1.5;color:#fff;vertical-align:middle;background:#444 url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;border:1px solid #222;border-radius:.25rem;appearance:none}.custom-select:focus{border-color:#739ac2;outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.custom-select:focus::-ms-value{color:#fff;background-color:#444}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#888;background-color:#ebebeb}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #fff}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.82031rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.17188rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#739ac2;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#2b2b2b}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#adb5bd;background-color:#444;border:1px solid #222;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#adb5bd;content:"Browse";background-color:#444;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#375a7f;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#97b3d2}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#375a7f;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#97b3d2}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#375a7f;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#97b3d2}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 2rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#adb5bd;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #444}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#444 #444 transparent}.nav-tabs .nav-link.disabled{color:#adb5bd;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#fff;background-color:#222;border-color:#444 #444 transparent}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#375a7f}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:1rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.32422rem;padding-bottom:.32422rem;margin-right:1rem;font-size:1.17188rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.17188rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:#fff}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:#fff}.navbar-light .navbar-nav .nav-link{color:rgba(255,255,255,.6)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:#fff}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:#fff}.navbar-light .navbar-toggler{color:rgba(255,255,255,.6);border-color:rgba(34,34,34,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.6%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(255,255,255,.6)}.navbar-light .navbar-text a{color:#fff}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:#fff}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.6)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:#fff}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.6);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.6%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.6)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#303030;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-body{flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:#444;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:#444;border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img,.card-img-bottom,.card-img-top{flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{column-count:3;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#444;border-radius:.25rem}.breadcrumb-item{display:flex}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#888;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#888}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:0;line-height:1.25;color:#fff;background-color:#00bc8c;border:0 solid transparent}.page-link:hover{z-index:2;color:#fff;text-decoration:none;background-color:#00efb2;border-color:transparent}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#00efb2;border-color:transparent}.page-item.disabled .page-link{color:#fff;pointer-events:none;cursor:auto;background-color:#007053;border-color:transparent}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.17188rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.82031rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#375a7f}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#28415b}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.5)}.badge-secondary{color:#fff;background-color:#444}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#2b2b2b}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(68,68,68,.5)}.badge-success{color:#fff;background-color:#00bc8c}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#008966}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,188,140,.5)}.badge-info{color:#fff;background-color:#3498db}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#217dbb}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,152,219,.5)}.badge-warning{color:#fff;background-color:#f39c12}a.badge-warning:focus,a.badge-warning:hover{color:#fff;background-color:#c87f0a}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(243,156,18,.5)}.badge-danger{color:#fff;background-color:#e74c3c}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#d62c1a}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(231,76,60,.5)}.badge-light{color:#fff;background-color:#303030}a.badge-light:focus,a.badge-light:hover{color:#fff;background-color:#171717}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(48,48,48,.5)}.badge-dark{color:#222;background-color:#dee2e6}a.badge-dark:focus,a.badge-dark:hover{color:#222;background-color:#c1c9d0}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(222,226,230,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#303030;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3.90625rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#1d2f42;background-color:#d7dee5;border-color:#c7d1db}.alert-primary hr{border-top-color:#b7c4d1}.alert-primary .alert-link{color:#0d161f}.alert-secondary{color:#232323;background-color:#dadada;border-color:#cbcbcb}.alert-secondary hr{border-top-color:#bebebe}.alert-secondary .alert-link{color:#0a0a0a}.alert-success{color:#006249;background-color:#ccf2e8;border-color:#b8ecdf}.alert-success hr{border-top-color:#a4e7d6}.alert-success .alert-link{color:#002f23}.alert-info{color:#1b4f72;background-color:#d6eaf8;border-color:#c6e2f5}.alert-info hr{border-top-color:#b0d7f1}.alert-info .alert-link{color:#113249}.alert-warning{color:#7e5109;background-color:#fdebd0;border-color:#fce3bd}.alert-warning hr{border-top-color:#fbd9a5}.alert-warning .alert-link{color:#4e3206}.alert-danger{color:#78281f;background-color:#fadbd8;border-color:#f8cdc8}.alert-danger hr{border-top-color:#f5b8b1}.alert-danger .alert-link{color:#4f1a15}.alert-light{color:#191919;background-color:#d6d6d6;border-color:#c5c5c5}.alert-light hr{border-top-color:#b8b8b8}.alert-light .alert-link{color:#000}.alert-dark{color:#737678;background-color:#f8f9fa;border-color:#f6f7f8}.alert-dark hr{border-top-color:#e8eaed}.alert-dark .alert-link{color:#5a5c5e}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.70312rem;background-color:#444;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#375a7f;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#444;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#444;text-decoration:none;background-color:#444}.list-group-item-action:active{color:#dee2e6;background-color:#ebebeb}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#303030;border:1px solid #444}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#888;pointer-events:none;background-color:#303030}.list-group-item.active{z-index:2;color:#fff;background-color:#375a7f;border-color:#375a7f}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#1d2f42;background-color:#c7d1db}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#1d2f42;background-color:#b7c4d1}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#1d2f42;border-color:#1d2f42}.list-group-item-secondary{color:#232323;background-color:#cbcbcb}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#232323;background-color:#bebebe}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#232323;border-color:#232323}.list-group-item-success{color:#006249;background-color:#b8ecdf}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#006249;background-color:#a4e7d6}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#006249;border-color:#006249}.list-group-item-info{color:#1b4f72;background-color:#c6e2f5}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#1b4f72;background-color:#b0d7f1}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#1b4f72;border-color:#1b4f72}.list-group-item-warning{color:#7e5109;background-color:#fce3bd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#7e5109;background-color:#fbd9a5}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#7e5109;border-color:#7e5109}.list-group-item-danger{color:#78281f;background-color:#f8cdc8}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#78281f;background-color:#f5b8b1}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#78281f;border-color:#78281f}.list-group-item-light{color:#191919;background-color:#c5c5c5}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#191919;background-color:#b8b8b8}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#191919;border-color:#191919}.list-group-item-dark{color:#737678;background-color:#f6f7f8}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#737678;background-color:#e8eaed}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#737678;border-color:#737678}.close{float:right;font-size:1.40625rem;font-weight:700;line-height:1;color:#fff;text-shadow:none;opacity:.5}.close:hover{color:#fff;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:#444;background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:flex;align-items:center;padding:.25rem .75rem;color:#888;background-color:#303030;background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{flex-direction:column;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#303030;background-clip:padding-box;border:1px solid #444;border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:flex-start;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #444;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #444;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem);height:min-content}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.82031rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.82031rem;word-wrap:break-word;background-color:#303030;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#303030}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#303030}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#303030}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #444}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#303030}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:.9375rem;background-color:#444;border-bottom:1px solid #373737;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#dee2e6}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#375a7f!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#28415b!important}.bg-secondary{background-color:#444!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#2b2b2b!important}.bg-success{background-color:#00bc8c!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#008966!important}.bg-info{background-color:#3498db!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#217dbb!important}.bg-warning{background-color:#f39c12!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#c87f0a!important}.bg-danger{background-color:#e74c3c!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#d62c1a!important}.bg-light{background-color:#303030!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#171717!important}.bg-dark{background-color:#dee2e6!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#c1c9d0!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#375a7f!important}.border-secondary{border-color:#444!important}.border-success{border-color:#00bc8c!important}.border-info{border-color:#3498db!important}.border-warning{border-color:#f39c12!important}.border-danger{border-color:#e74c3c!important}.border-light{border-color:#303030!important}.border-dark{border-color:#dee2e6!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#375a7f!important}a.text-primary:focus,a.text-primary:hover{color:#20344a!important}.text-secondary{color:#444!important}a.text-secondary:focus,a.text-secondary:hover{color:#1e1e1e!important}.text-success{color:#00bc8c!important}a.text-success:focus,a.text-success:hover{color:#007053!important}.text-info{color:#3498db!important}a.text-info:focus,a.text-info:hover{color:#1d6fa5!important}.text-warning{color:#f39c12!important}a.text-warning:focus,a.text-warning:hover{color:#b06f09!important}.text-danger{color:#e74c3c!important}a.text-danger:focus,a.text-danger:hover{color:#bf2718!important}.text-light{color:#303030!important}a.text-light:focus,a.text-light:hover{color:#0a0a0a!important}.text-dark{color:#dee2e6!important}a.text-dark:focus,a.text-dark:hover{color:#b2bcc5!important}.text-body{color:#dee2e6!important}.text-muted{color:#888!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#444}.table .thead-dark th{color:inherit;border-color:#444}}
diff --git a/src/assets/css/themes/darkly.min.css b/src/assets/css/themes/darkly.min.css
deleted file mode 100644 (file)
index de1f698..0000000
+++ /dev/null
@@ -1 +0,0 @@
-:root{--blue:#375a7f;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#e74c3c;--orange:#fd7e14;--yellow:#f39c12;--green:#00bc8c;--teal:#20c997;--cyan:#3498db;--white:#fff;--gray:#888;--gray-dark:#303030;--primary:#375a7f;--secondary:#444;--success:#00bc8c;--info:#3498db;--warning:#f39c12;--danger:#e74c3c;--light:#303030;--dark:#dee2e6;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:"Lato",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-size:.9375rem;font-weight:400;line-height:1.5;color:#dee2e6;text-align:left;background-color:#222}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#00bc8c;text-decoration:none;background-color:transparent}a:hover{color:#007053;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#888;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:3rem}.h2,h2{font-size:2.5rem}.h3,h3{font-size:2rem}.h4,h4{font-size:1.40625rem}.h5,h5{font-size:1.17188rem}.h6,h6{font-size:.9375rem}.lead{font-size:1.17188rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#333}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.17188rem}.blockquote-footer{display:block;font-size:80%;color:#888}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#222;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#888}code{font-size:87.5%;color:#e83e8c;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#fff;background-color:#222;border-radius:.2rem}kbd kbd{padding:0;font-size:100%;font-weight:700}pre{display:block;font-size:87.5%;color:inherit}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-auto{flex:0 0 auto;width:auto;max-width:100%}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-md-auto{flex:0 0 auto;width:auto;max-width:100%}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;margin-bottom:1rem;color:#dee2e6}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #444}.table thead th{vertical-align:bottom;border-bottom:2px solid #444}.table tbody+tbody{border-top:2px solid #444}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #444}.table-bordered td,.table-bordered th{border:1px solid #444}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:#303030}.table-hover tbody tr:hover{color:#dee2e6;background-color:rgba(0,0,0,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#c7d1db}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#97a9bc}.table-hover .table-primary:hover{background-color:#b7c4d1}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#b7c4d1}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#cbcbcb}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#9e9e9e}.table-hover .table-secondary:hover{background-color:#bebebe}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#bebebe}.table-success,.table-success>td,.table-success>th{background-color:#b8ecdf}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#7adcc3}.table-hover .table-success:hover{background-color:#a4e7d6}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#a4e7d6}.table-info,.table-info>td,.table-info>th{background-color:#c6e2f5}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#95c9ec}.table-hover .table-info:hover{background-color:#b0d7f1}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#b0d7f1}.table-warning,.table-warning>td,.table-warning>th{background-color:#fce3bd}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#f9cc84}.table-hover .table-warning:hover{background-color:#fbd9a5}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#fbd9a5}.table-danger,.table-danger>td,.table-danger>th{background-color:#f8cdc8}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#f3a29a}.table-hover .table-danger:hover{background-color:#f5b8b1}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f5b8b1}.table-light,.table-light>td,.table-light>th{background-color:#c5c5c5}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#939393}.table-hover .table-light:hover{background-color:#b8b8b8}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#b8b8b8}.table-dark,.table-dark>td,.table-dark>th{background-color:#f6f7f8}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#eef0f2}.table-hover .table-dark:hover{background-color:#e8eaed}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#e8eaed}.table-active,.table-active>td,.table-active>th{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover{background-color:rgba(0,0,0,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(0,0,0,.075)}.table .thead-dark th{color:#fff;background-color:#303030;border-color:#434343}.table .thead-light th{color:#444;background-color:#ebebeb;border-color:#444}.table-dark{color:#fff;background-color:#303030}.table-dark td,.table-dark th,.table-dark thead th{border-color:#434343}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{color:#fff;background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:.9375rem;font-weight:400;line-height:1.5;color:#fff;background-color:#444;background-clip:padding-box;border:1px solid #222;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #fff}.form-control:focus{color:#fff;background-color:#444;border-color:#739ac2;outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.form-control::placeholder{color:#888;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#2b2b2b;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{appearance:none}select.form-control:focus::-ms-value{color:#fff;background-color:#444}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.17188rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.82031rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:.9375rem;line-height:1.5;color:#dee2e6;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.82031rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.17188rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#888}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#00bc8c}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.82031rem;line-height:1.5;color:#fff;background-color:rgba(0,188,140,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#00bc8c;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2300bc8c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#00bc8c;box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#00bc8c;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%2300bc8c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #444 no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#00bc8c;box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#00bc8c}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#00bc8c}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#00bc8c}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#00efb2;background-color:#00efb2}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#00bc8c}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#00bc8c}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#00bc8c;box-shadow:0 0 0 .2rem rgba(0,188,140,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#e74c3c}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.82031rem;line-height:1.5;color:#fff;background-color:rgba(231,76,60,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#e74c3c;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23e74c3c' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e74c3c' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#e74c3c;box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#e74c3c;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23e74c3c' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23e74c3c' stroke='none'/%3e%3c/svg%3e") #444 no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#e74c3c;box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#e74c3c}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#e74c3c}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#e74c3c}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#ed7669;background-color:#ed7669}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#e74c3c}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#e74c3c}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#e74c3c;box-shadow:0 0 0 .2rem rgba(231,76,60,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#dee2e6;text-align:center;vertical-align:middle;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:.9375rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#dee2e6;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.btn.disabled,.btn:disabled{opacity:.65}.btn:not(:disabled):not(.disabled){cursor:pointer}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-primary:hover{color:#fff;background-color:#2b4764;border-color:#28415b}.btn-primary.focus,.btn-primary:focus{color:#fff;background-color:#2b4764;border-color:#28415b;box-shadow:0 0 0 .2rem rgba(85,115,146,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#28415b;border-color:#243a53}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(85,115,146,.5)}.btn-secondary{color:#fff;background-color:#444;border-color:#444}.btn-secondary:hover{color:#fff;background-color:#313131;border-color:#2b2b2b}.btn-secondary.focus,.btn-secondary:focus{color:#fff;background-color:#313131;border-color:#2b2b2b;box-shadow:0 0 0 .2rem rgba(96,96,96,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#fff;background-color:#444;border-color:#444}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#2b2b2b;border-color:#242424}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(96,96,96,.5)}.btn-success{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-success:hover{color:#fff;background-color:#009670;border-color:#008966}.btn-success.focus,.btn-success:focus{color:#fff;background-color:#009670;border-color:#008966;box-shadow:0 0 0 .2rem rgba(38,198,157,.5)}.btn-success.disabled,.btn-success:disabled{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#008966;border-color:#007c5d}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(38,198,157,.5)}.btn-info{color:#fff;background-color:#3498db;border-color:#3498db}.btn-info:hover{color:#fff;background-color:#2384c6;border-color:#217dbb}.btn-info.focus,.btn-info:focus{color:#fff;background-color:#2384c6;border-color:#217dbb;box-shadow:0 0 0 .2rem rgba(82,167,224,.5)}.btn-info.disabled,.btn-info:disabled{color:#fff;background-color:#3498db;border-color:#3498db}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#217dbb;border-color:#1f76b0}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,167,224,.5)}.btn-warning{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-warning:hover{color:#fff;background-color:#d4860b;border-color:#c87f0a}.btn-warning.focus,.btn-warning:focus{color:#fff;background-color:#d4860b;border-color:#c87f0a;box-shadow:0 0 0 .2rem rgba(245,171,54,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#c87f0a;border-color:#bc770a}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(245,171,54,.5)}.btn-danger{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:hover{color:#fff;background-color:#e12e1c;border-color:#d62c1a}.btn-danger.focus,.btn-danger:focus{color:#fff;background-color:#e12e1c;border-color:#d62c1a;box-shadow:0 0 0 .2rem rgba(235,103,89,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#d62c1a;border-color:#ca2a19}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(235,103,89,.5)}.btn-light{color:#fff;background-color:#303030;border-color:#303030}.btn-light:hover{color:#fff;background-color:#1d1d1d;border-color:#171717}.btn-light.focus,.btn-light:focus{color:#fff;background-color:#1d1d1d;border-color:#171717;box-shadow:0 0 0 .2rem rgba(79,79,79,.5)}.btn-light.disabled,.btn-light:disabled{color:#fff;background-color:#303030;border-color:#303030}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#fff;background-color:#171717;border-color:#101010}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(79,79,79,.5)}.btn-dark{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-dark:hover{color:#222;background-color:#c8cfd6;border-color:#c1c9d0}.btn-dark.focus,.btn-dark:focus{color:#222;background-color:#c8cfd6;border-color:#c1c9d0;box-shadow:0 0 0 .2rem rgba(194,197,201,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#222;background-color:#c1c9d0;border-color:#bac2cb}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(194,197,201,.5)}.btn-outline-primary{color:#375a7f;border-color:#375a7f}.btn-outline-primary:hover{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(55,90,127,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#375a7f;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#fff;background-color:#375a7f;border-color:#375a7f}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(55,90,127,.5)}.btn-outline-secondary{color:#444;border-color:#444}.btn-outline-secondary:hover{color:#fff;background-color:#444;border-color:#444}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(68,68,68,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#444;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#fff;background-color:#444;border-color:#444}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(68,68,68,.5)}.btn-outline-success{color:#00bc8c;border-color:#00bc8c}.btn-outline-success:hover{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(0,188,140,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#00bc8c;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#fff;background-color:#00bc8c;border-color:#00bc8c}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(0,188,140,.5)}.btn-outline-info{color:#3498db;border-color:#3498db}.btn-outline-info:hover{color:#fff;background-color:#3498db;border-color:#3498db}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(52,152,219,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#3498db;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#fff;background-color:#3498db;border-color:#3498db}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(52,152,219,.5)}.btn-outline-warning{color:#f39c12;border-color:#f39c12}.btn-outline-warning:hover{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(243,156,18,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#f39c12;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#fff;background-color:#f39c12;border-color:#f39c12}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(243,156,18,.5)}.btn-outline-danger{color:#e74c3c;border-color:#e74c3c}.btn-outline-danger:hover{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(231,76,60,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#e74c3c;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#fff;background-color:#e74c3c;border-color:#e74c3c}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(231,76,60,.5)}.btn-outline-light{color:#303030;border-color:#303030}.btn-outline-light:hover{color:#fff;background-color:#303030;border-color:#303030}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(48,48,48,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#303030;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#fff;background-color:#303030;border-color:#303030}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(48,48,48,.5)}.btn-outline-dark{color:#dee2e6;border-color:#dee2e6}.btn-outline-dark:hover{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(222,226,230,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#dee2e6;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#222;background-color:#dee2e6;border-color:#dee2e6}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(222,226,230,.5)}.btn-link{font-weight:400;color:#00bc8c;text-decoration:none}.btn-link:hover{color:#007053;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#888;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.17188rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.82031rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:.9375rem;color:#dee2e6;text-align:left;list-style:none;background-color:#222;background-clip:padding-box;border:1px solid #444;border-radius:.25rem}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #444}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#fff;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#fff;text-decoration:none;background-color:#375a7f}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#375a7f}.dropdown-item.disabled,.dropdown-item:disabled{color:#888;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.82031rem;color:#888;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#fff}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:flex;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:.9375rem;font-weight:400;line-height:1.5;color:#adb5bd;text-align:center;white-space:nowrap;background-color:#444;border:1px solid #222;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.17188rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.82031rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.40625rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.20312rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#fff;border-color:#375a7f;background-color:#375a7f}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#739ac2}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#fff;background-color:#97b3d2;border-color:#97b3d2}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#888}.custom-control-input:disabled~.custom-control-label::before,.custom-control-input[disabled]~.custom-control-label::before{background-color:#2b2b2b}.custom-control-label{position:relative;margin-bottom:0;vertical-align:top}.custom-control-label::before{position:absolute;top:.20312rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#444;border:#adb5bd solid 1px}.custom-control-label::after{position:absolute;top:.20312rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#375a7f;background-color:#375a7f}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23fff' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.20312rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#adb5bd;border-radius:.5rem;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-switch .custom-control-label::after{transition:none}}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#444;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(55,90,127,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:.9375rem;font-weight:400;line-height:1.5;color:#fff;vertical-align:middle;background:#444 url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23303030' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;border:1px solid #222;border-radius:.25rem;appearance:none}.custom-select:focus{border-color:#739ac2;outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.custom-select:focus::-ms-value{color:#fff;background-color:#444}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#888;background-color:#ebebeb}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #fff}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.82031rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.17188rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#739ac2;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#2b2b2b}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#adb5bd;background-color:#444;border:1px solid #222;border-radius:.25rem}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#adb5bd;content:"Browse";background-color:#444;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #222,0 0 0 .2rem rgba(55,90,127,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#375a7f;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:#97b3d2}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#375a7f;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{transition:none}}.custom-range::-moz-range-thumb:active{background-color:#97b3d2}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#375a7f;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{transition:none}}.custom-range::-ms-thumb:active{background-color:#97b3d2}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#dee2e6;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#adb5bd}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#adb5bd}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 2rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#adb5bd;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #444}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#444 #444 transparent}.nav-tabs .nav-link.disabled{color:#adb5bd;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#fff;background-color:#222;border-color:#444 #444 transparent}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#375a7f}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:1rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.32422rem;padding-bottom:.32422rem;margin-right:1rem;font-size:1.17188rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.17188rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:#fff}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:#fff}.navbar-light .navbar-nav .nav-link{color:rgba(255,255,255,.6)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:#fff}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:#fff}.navbar-light .navbar-toggler{color:rgba(255,255,255,.6);border-color:rgba(34,34,34,.1)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.6%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:rgba(255,255,255,.6)}.navbar-light .navbar-text a{color:#fff}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:#fff}.navbar-dark .navbar-brand{color:#fff}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.6)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:#fff}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.6);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.6%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(255,255,255,.6)}.navbar-dark .navbar-text a{color:#fff}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#303030;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-body{flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:#444;border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:#444;border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img,.card-img-bottom,.card-img-top{flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{column-count:3;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#444;border-radius:.25rem}.breadcrumb-item{display:flex}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#888;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#888}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:0;line-height:1.25;color:#fff;background-color:#00bc8c;border:0 solid transparent}.page-link:hover{z-index:2;color:#fff;text-decoration:none;background-color:#00efb2;border-color:transparent}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#fff;background-color:#00efb2;border-color:transparent}.page-item.disabled .page-link{color:#fff;pointer-events:none;cursor:auto;background-color:#007053;border-color:transparent}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.17188rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.82031rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.badge{transition:none}}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#fff;background-color:#375a7f}a.badge-primary:focus,a.badge-primary:hover{color:#fff;background-color:#28415b}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(55,90,127,.5)}.badge-secondary{color:#fff;background-color:#444}a.badge-secondary:focus,a.badge-secondary:hover{color:#fff;background-color:#2b2b2b}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(68,68,68,.5)}.badge-success{color:#fff;background-color:#00bc8c}a.badge-success:focus,a.badge-success:hover{color:#fff;background-color:#008966}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(0,188,140,.5)}.badge-info{color:#fff;background-color:#3498db}a.badge-info:focus,a.badge-info:hover{color:#fff;background-color:#217dbb}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(52,152,219,.5)}.badge-warning{color:#fff;background-color:#f39c12}a.badge-warning:focus,a.badge-warning:hover{color:#fff;background-color:#c87f0a}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(243,156,18,.5)}.badge-danger{color:#fff;background-color:#e74c3c}a.badge-danger:focus,a.badge-danger:hover{color:#fff;background-color:#d62c1a}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(231,76,60,.5)}.badge-light{color:#fff;background-color:#303030}a.badge-light:focus,a.badge-light:hover{color:#fff;background-color:#171717}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(48,48,48,.5)}.badge-dark{color:#222;background-color:#dee2e6}a.badge-dark:focus,a.badge-dark:hover{color:#222;background-color:#c1c9d0}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(222,226,230,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#303030;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3.90625rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#1d2f42;background-color:#d7dee5;border-color:#c7d1db}.alert-primary hr{border-top-color:#b7c4d1}.alert-primary .alert-link{color:#0d161f}.alert-secondary{color:#232323;background-color:#dadada;border-color:#cbcbcb}.alert-secondary hr{border-top-color:#bebebe}.alert-secondary .alert-link{color:#0a0a0a}.alert-success{color:#006249;background-color:#ccf2e8;border-color:#b8ecdf}.alert-success hr{border-top-color:#a4e7d6}.alert-success .alert-link{color:#002f23}.alert-info{color:#1b4f72;background-color:#d6eaf8;border-color:#c6e2f5}.alert-info hr{border-top-color:#b0d7f1}.alert-info .alert-link{color:#113249}.alert-warning{color:#7e5109;background-color:#fdebd0;border-color:#fce3bd}.alert-warning hr{border-top-color:#fbd9a5}.alert-warning .alert-link{color:#4e3206}.alert-danger{color:#78281f;background-color:#fadbd8;border-color:#f8cdc8}.alert-danger hr{border-top-color:#f5b8b1}.alert-danger .alert-link{color:#4f1a15}.alert-light{color:#191919;background-color:#d6d6d6;border-color:#c5c5c5}.alert-light hr{border-top-color:#b8b8b8}.alert-light .alert-link{color:#000}.alert-dark{color:#737678;background-color:#f8f9fa;border-color:#f6f7f8}.alert-dark hr{border-top-color:#e8eaed}.alert-dark .alert-link{color:#5a5c5e}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.70312rem;background-color:#444;border-radius:.25rem}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#375a7f;transition:width .6s ease}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#444;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#444;text-decoration:none;background-color:#444}.list-group-item-action:active{color:#dee2e6;background-color:#ebebeb}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#303030;border:1px solid #444}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#888;pointer-events:none;background-color:#303030}.list-group-item.active{z-index:2;color:#fff;background-color:#375a7f;border-color:#375a7f}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#1d2f42;background-color:#c7d1db}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#1d2f42;background-color:#b7c4d1}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#1d2f42;border-color:#1d2f42}.list-group-item-secondary{color:#232323;background-color:#cbcbcb}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#232323;background-color:#bebebe}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#232323;border-color:#232323}.list-group-item-success{color:#006249;background-color:#b8ecdf}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#006249;background-color:#a4e7d6}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#006249;border-color:#006249}.list-group-item-info{color:#1b4f72;background-color:#c6e2f5}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#1b4f72;background-color:#b0d7f1}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#1b4f72;border-color:#1b4f72}.list-group-item-warning{color:#7e5109;background-color:#fce3bd}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#7e5109;background-color:#fbd9a5}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#7e5109;border-color:#7e5109}.list-group-item-danger{color:#78281f;background-color:#f8cdc8}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#78281f;background-color:#f5b8b1}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#78281f;border-color:#78281f}.list-group-item-light{color:#191919;background-color:#c5c5c5}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#191919;background-color:#b8b8b8}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#191919;border-color:#191919}.list-group-item-dark{color:#737678;background-color:#f6f7f8}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#737678;background-color:#e8eaed}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#737678;border-color:#737678}.close{float:right;font-size:1.40625rem;font-weight:700;line-height:1;color:#fff;text-shadow:none;opacity:.5}.close:hover{color:#fff;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:#444;background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(0,0,0,.1);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:flex;align-items:center;padding:.25rem .75rem;color:#888;background-color:#303030;background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{flex-direction:column;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#303030;background-clip:padding-box;border:1px solid #444;border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:flex-start;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #444;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #444;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem);height:min-content}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.82031rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:Lato,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.82031rem;word-wrap:break-word;background-color:#303030;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#303030}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#303030}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#303030}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #444}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#303030}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:.9375rem;background-color:#444;border-bottom:1px solid #373737;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#dee2e6}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;color:#fff;text-align:center;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators li{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#375a7f!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#28415b!important}.bg-secondary{background-color:#444!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#2b2b2b!important}.bg-success{background-color:#00bc8c!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#008966!important}.bg-info{background-color:#3498db!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#217dbb!important}.bg-warning{background-color:#f39c12!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#c87f0a!important}.bg-danger{background-color:#e74c3c!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#d62c1a!important}.bg-light{background-color:#303030!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#171717!important}.bg-dark{background-color:#dee2e6!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#c1c9d0!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #dee2e6!important}.border-top{border-top:1px solid #dee2e6!important}.border-right{border-right:1px solid #dee2e6!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-left{border-left:1px solid #dee2e6!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#375a7f!important}.border-secondary{border-color:#444!important}.border-success{border-color:#00bc8c!important}.border-info{border-color:#3498db!important}.border-warning{border-color:#f39c12!important}.border-danger{border-color:#e74c3c!important}.border-light{border-color:#303030!important}.border-dark{border-color:#dee2e6!important}.border-white{border-color:#fff!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.text-primary{color:#375a7f!important}a.text-primary:focus,a.text-primary:hover{color:#20344a!important}.text-secondary{color:#444!important}a.text-secondary:focus,a.text-secondary:hover{color:#1e1e1e!important}.text-success{color:#00bc8c!important}a.text-success:focus,a.text-success:hover{color:#007053!important}.text-info{color:#3498db!important}a.text-info:focus,a.text-info:hover{color:#1d6fa5!important}.text-warning{color:#f39c12!important}a.text-warning:focus,a.text-warning:hover{color:#b06f09!important}.text-danger{color:#e74c3c!important}a.text-danger:focus,a.text-danger:hover{color:#bf2718!important}.text-light{color:#303030!important}a.text-light:focus,a.text-light:hover{color:#0a0a0a!important}.text-dark{color:#dee2e6!important}a.text-dark:focus,a.text-dark:hover{color:#b2bcc5!important}.text-body{color:#dee2e6!important}.text-muted{color:#888!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:rgba(255,255,255,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#444}.table .thead-dark th{color:inherit;border-color:#444}}
diff --git a/src/assets/css/themes/litely-red.css b/src/assets/css/themes/litely-red.css
new file mode 100644 (file)
index 0000000..2702eb1
--- /dev/null
@@ -0,0 +1,8816 @@
+:root {
+ --blue:#007bff;
+ --indigo:#6610f2;
+ --purple:#6f42c1;
+ --pink:#e83e8c;
+ --red:#d8486a;
+ --orange:#f1641e;
+ --yellow:#ffc107;
+ --green:#00c853;
+ --teal:#20c997;
+ --cyan:#02bdc2;
+ --white:#ffffff;
+ --gray:#6c757d;
+ --gray-dark:#343a40;
+ --primary:#d84848;
+ --secondary:#00c853;
+ --success:#6610f2;
+ --info:#007bff;
+ --warning:#ffc107;
+ --danger:#873208;
+ --light:#f8f9fa;
+ --dark:#343a40;
+ --breakpoint-xs:0;
+ --breakpoint-sm:576px;
+ --breakpoint-md:768px;
+ --breakpoint-lg:992px;
+ --breakpoint-xl:1200px;
+ --font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Droid Sans","Segoe UI","Helvetica",Arial,sans-serif;
+ --font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace
+}
+*,
+::after,
+::before {
+ box-sizing:border-box
+}
+html {
+ font-family:sans-serif;
+ line-height:1.15;
+ -webkit-text-size-adjust:100%;
+ -webkit-tap-highlight-color:rgba(34,34,34,0)
+}
+article,
+aside,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+nav,
+section {
+ display:block
+}
+body {
+ margin:0;
+ font-family:-apple-system,BlinkMacSystemFont,"Droid Sans","Segoe UI",Helvetica,Arial,sans-serif;
+ font-size:1rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#495057;
+ text-align:left;
+ background-color:#fff
+}
+[tabindex="-1"]:focus:not(:focus-visible) {
+ outline:0!important
+}
+hr {
+ box-sizing:content-box;
+ height:0;
+ overflow:visible
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-top:0;
+ margin-bottom:.5rem
+}
+p {
+ margin-top:0;
+ margin-bottom:1rem
+}
+abbr[data-original-title],
+abbr[title] {
+ text-decoration:underline;
+ text-decoration:underline dotted;
+ cursor:help;
+ border-bottom:0;
+ text-decoration-skip-ink:none
+}
+address {
+ margin-bottom:1rem;
+ font-style:normal;
+ line-height:inherit
+}
+dl,
+ol,
+ul {
+ margin-top:0;
+ margin-bottom:1rem
+}
+ol ol,
+ol ul,
+ul ol,
+ul ul {
+ margin-bottom:0
+}
+dt {
+ font-weight:600
+}
+dd {
+ margin-bottom:.5rem;
+ margin-left:0
+}
+blockquote {
+ margin:0 0 1rem
+}
+b,
+strong {
+ font-weight:bolder
+}
+small {
+ font-size:80%
+}
+sub,
+sup {
+ position:relative;
+ font-size:75%;
+ line-height:0;
+ vertical-align:baseline
+}
+sub {
+ bottom:-.25em
+}
+sup {
+ top:-.5em
+}
+a {
+ color:#d84848;
+ text-decoration:none;
+ background-color:transparent
+}
+a:hover {
+ color:#b70b0b;
+ text-decoration:underline
+}
+a:not([href]) {
+ color:inherit;
+ text-decoration:none
+}
+a:not([href]):hover {
+ color:inherit;
+ text-decoration:none
+}
+code,
+kbd,
+pre,
+samp {
+ font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
+ font-size:1em
+}
+pre {
+ margin-top:0;
+ margin-bottom:1rem;
+ overflow:auto;
+ -ms-overflow-style:scrollbar
+}
+figure {
+ margin:0 0 1rem
+}
+img {
+ vertical-align:middle;
+ border-style:none
+}
+svg {
+ overflow:hidden;
+ vertical-align:middle
+}
+table {
+ border-collapse:collapse
+}
+caption {
+ padding-top:.75rem;
+ padding-bottom:.75rem;
+ color:#6c757d;
+ text-align:left;
+ caption-side:bottom
+}
+th {
+ text-align:inherit
+}
+label {
+ display:inline-block;
+ margin-bottom:.5rem
+}
+button {
+ border-radius:0
+}
+button:focus {
+ outline:1px dotted;
+ outline:5px auto -webkit-focus-ring-color
+}
+button,
+input,
+optgroup,
+select,
+textarea {
+ margin:0;
+ font-family:inherit;
+ font-size:inherit;
+ line-height:inherit
+}
+button,
+input {
+ overflow:visible
+}
+button,
+select {
+ text-transform:none
+}
+[role=button] {
+ cursor:pointer
+}
+select {
+ word-wrap:normal
+}
+[type=button],
+[type=reset],
+[type=submit],
+button {
+ -webkit-appearance:button
+}
+[type=button]:not(:disabled),
+[type=reset]:not(:disabled),
+[type=submit]:not(:disabled),
+button:not(:disabled) {
+ cursor:pointer
+}
+[type=button]::-moz-focus-inner,
+[type=reset]::-moz-focus-inner,
+[type=submit]::-moz-focus-inner,
+button::-moz-focus-inner {
+ padding:0;
+ border-style:none
+}
+input[type=checkbox],
+input[type=radio] {
+ box-sizing:border-box;
+ padding:0
+}
+textarea {
+ overflow:auto;
+ resize:vertical
+}
+fieldset {
+ min-width:0;
+ padding:0;
+ margin:0;
+ border:0
+}
+legend {
+ display:block;
+ width:100%;
+ max-width:100%;
+ padding:0;
+ margin-bottom:.5rem;
+ font-size:1.5rem;
+ line-height:inherit;
+ color:inherit;
+ white-space:normal
+}
+progress {
+ vertical-align:baseline
+}
+[type=number]::-webkit-inner-spin-button,
+[type=number]::-webkit-outer-spin-button {
+ height:auto
+}
+[type=search] {
+ outline-offset:-2px;
+ -webkit-appearance:none
+}
+[type=search]::-webkit-search-decoration {
+ -webkit-appearance:none
+}
+::-webkit-file-upload-button {
+ font:inherit;
+ -webkit-appearance:button
+}
+output {
+ display:inline-block
+}
+summary {
+ display:list-item;
+ cursor:pointer
+}
+template {
+ display:none
+}
+[hidden] {
+ display:none!important
+}
+.h1,
+.h2,
+.h3,
+.h4,
+.h5,
+.h6,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ margin-bottom:.5rem;
+ font-weight:500;
+ line-height:1.2;
+ color:#495057
+}
+.h1,
+h1 {
+ font-size:2.5rem
+}
+.h2,
+h2 {
+ font-size:2rem
+}
+.h3,
+h3 {
+ font-size:1.75rem
+}
+.h4,
+h4 {
+ font-size:1.5rem
+}
+.h5,
+h5 {
+ font-size:1.25rem
+}
+.h6,
+h6 {
+ font-size:1rem
+}
+.lead {
+ font-size:1.25rem;
+ font-weight:300
+}
+.display-1 {
+ font-size:6rem;
+ font-weight:300;
+ line-height:1.2
+}
+.display-2 {
+ font-size:5.5rem;
+ font-weight:300;
+ line-height:1.2
+}
+.display-3 {
+ font-size:4.5rem;
+ font-weight:300;
+ line-height:1.2
+}
+.display-4 {
+ font-size:3.5rem;
+ font-weight:300;
+ line-height:1.2
+}
+hr {
+ margin-top:1rem;
+ margin-bottom:1rem;
+ border:0;
+ border-top:1px solid rgba(34,34,34,.1)
+}
+.small,
+small {
+ font-size:80%;
+ font-weight:400
+}
+.mark,
+mark {
+ padding:.2em;
+ background-color:#fffcef
+}
+.list-unstyled {
+ padding-left:0;
+ list-style:none
+}
+.list-inline {
+ padding-left:0;
+ list-style:none
+}
+.list-inline-item {
+ display:inline-block
+}
+.list-inline-item:not(:last-child) {
+ margin-right:.5rem
+}
+.initialism {
+ font-size:90%;
+ text-transform:uppercase
+}
+.blockquote {
+ margin-bottom:1rem;
+ font-size:1.25rem
+}
+.blockquote-footer {
+ display:block;
+ font-size:80%;
+ color:#6c757d
+}
+.blockquote-footer::before {
+ content:"\2014\00A0"
+}
+.img-fluid {
+ max-width:100%;
+ height:auto
+}
+.img-thumbnail {
+ padding:.25rem;
+ background-color:#fff;
+ border:1px solid #dee2e6;
+ border-radius:.5rem;
+ max-width:100%;
+ height:auto
+}
+.figure {
+ display:inline-block
+}
+.figure-img {
+ margin-bottom:.5rem;
+ line-height:1
+}
+.figure-caption {
+ font-size:90%;
+ color:#6c757d
+}
+code {
+ font-size:87.5%;
+ color:#e83e8c;
+ word-wrap:break-word
+}
+a>code {
+ color:inherit
+}
+kbd {
+ padding:.2rem .4rem;
+ font-size:87.5%;
+ color:#fff;
+ background-color:#212529;
+ border-radius:1rem
+}
+kbd kbd {
+ padding:0;
+ font-size:100%;
+ font-weight:600
+}
+pre {
+ display:block;
+ font-size:87.5%;
+ color:#212529
+}
+pre code {
+ font-size:inherit;
+ color:inherit;
+ word-break:normal
+}
+.pre-scrollable {
+ max-height:340px;
+ overflow-y:scroll
+}
+.container {
+ width:100%;
+ padding-right:15px;
+ padding-left:15px;
+ margin-right:auto;
+ margin-left:auto
+}
+@media (min-width:576px) {
+ .container {
+  max-width:540px
+ }
+}
+@media (min-width:768px) {
+ .container {
+  max-width:720px
+ }
+}
+@media (min-width:992px) {
+ .container {
+  max-width:960px
+ }
+}
+@media (min-width:1200px) {
+ .container {
+  max-width:1140px
+ }
+}
+.container-fluid,
+.container-lg,
+.container-md,
+.container-sm,
+.container-xl {
+ width:100%;
+ padding-right:15px;
+ padding-left:15px;
+ margin-right:auto;
+ margin-left:auto
+}
+@media (min-width:576px) {
+ .container,
+ .container-sm {
+  max-width:540px
+ }
+}
+@media (min-width:768px) {
+ .container,
+ .container-md,
+ .container-sm {
+  max-width:720px
+ }
+}
+@media (min-width:992px) {
+ .container,
+ .container-lg,
+ .container-md,
+ .container-sm {
+  max-width:960px
+ }
+}
+@media (min-width:1200px) {
+ .container,
+ .container-lg,
+ .container-md,
+ .container-sm,
+ .container-xl {
+  max-width:1140px
+ }
+}
+.row {
+ display:flex;
+ flex-wrap:wrap;
+ margin-right:-15px;
+ margin-left:-15px
+}
+.no-gutters {
+ margin-right:0;
+ margin-left:0
+}
+.no-gutters>.col,
+.no-gutters>[class*=col-] {
+ padding-right:0;
+ padding-left:0
+}
+.col,
+.col-1,
+.col-10,
+.col-11,
+.col-12,
+.col-2,
+.col-3,
+.col-4,
+.col-5,
+.col-6,
+.col-7,
+.col-8,
+.col-9,
+.col-auto,
+.col-lg,
+.col-lg-1,
+.col-lg-10,
+.col-lg-11,
+.col-lg-12,
+.col-lg-2,
+.col-lg-3,
+.col-lg-4,
+.col-lg-5,
+.col-lg-6,
+.col-lg-7,
+.col-lg-8,
+.col-lg-9,
+.col-lg-auto,
+.col-md,
+.col-md-1,
+.col-md-10,
+.col-md-11,
+.col-md-12,
+.col-md-2,
+.col-md-3,
+.col-md-4,
+.col-md-5,
+.col-md-6,
+.col-md-7,
+.col-md-8,
+.col-md-9,
+.col-md-auto,
+.col-sm,
+.col-sm-1,
+.col-sm-10,
+.col-sm-11,
+.col-sm-12,
+.col-sm-2,
+.col-sm-3,
+.col-sm-4,
+.col-sm-5,
+.col-sm-6,
+.col-sm-7,
+.col-sm-8,
+.col-sm-9,
+.col-sm-auto,
+.col-xl,
+.col-xl-1,
+.col-xl-10,
+.col-xl-11,
+.col-xl-12,
+.col-xl-2,
+.col-xl-3,
+.col-xl-4,
+.col-xl-5,
+.col-xl-6,
+.col-xl-7,
+.col-xl-8,
+.col-xl-9,
+.col-xl-auto {
+ position:relative;
+ width:100%;
+ padding-right:15px;
+ padding-left:15px
+}
+.col {
+ flex-basis:0;
+ flex-grow:1;
+ min-width:0;
+ max-width:100%
+}
+.row-cols-1>* {
+ flex:0 0 100%;
+ max-width:100%
+}
+.row-cols-2>* {
+ flex:0 0 50%;
+ max-width:50%
+}
+.row-cols-3>* {
+ flex:0 0 33.33333%;
+ max-width:33.33333%
+}
+.row-cols-4>* {
+ flex:0 0 25%;
+ max-width:25%
+}
+.row-cols-5>* {
+ flex:0 0 20%;
+ max-width:20%
+}
+.row-cols-6>* {
+ flex:0 0 16.66667%;
+ max-width:16.66667%
+}
+.col-auto {
+ flex:0 0 auto;
+ width:auto;
+ max-width:100%
+}
+.col-1 {
+ flex:0 0 8.33333%;
+ max-width:8.33333%
+}
+.col-2 {
+ flex:0 0 16.66667%;
+ max-width:16.66667%
+}
+.col-3 {
+ flex:0 0 25%;
+ max-width:25%
+}
+.col-4 {
+ flex:0 0 33.33333%;
+ max-width:33.33333%
+}
+.col-5 {
+ flex:0 0 41.66667%;
+ max-width:41.66667%
+}
+.col-6 {
+ flex:0 0 50%;
+ max-width:50%
+}
+.col-7 {
+ flex:0 0 58.33333%;
+ max-width:58.33333%
+}
+.col-8 {
+ flex:0 0 66.66667%;
+ max-width:66.66667%
+}
+.col-9 {
+ flex:0 0 75%;
+ max-width:75%
+}
+.col-10 {
+ flex:0 0 83.33333%;
+ max-width:83.33333%
+}
+.col-11 {
+ flex:0 0 91.66667%;
+ max-width:91.66667%
+}
+.col-12 {
+ flex:0 0 100%;
+ max-width:100%
+}
+.order-first {
+ order:-1
+}
+.order-last {
+ order:13
+}
+.order-0 {
+ order:0
+}
+.order-1 {
+ order:1
+}
+.order-2 {
+ order:2
+}
+.order-3 {
+ order:3
+}
+.order-4 {
+ order:4
+}
+.order-5 {
+ order:5
+}
+.order-6 {
+ order:6
+}
+.order-7 {
+ order:7
+}
+.order-8 {
+ order:8
+}
+.order-9 {
+ order:9
+}
+.order-10 {
+ order:10
+}
+.order-11 {
+ order:11
+}
+.order-12 {
+ order:12
+}
+.offset-1 {
+ margin-left:8.33333%
+}
+.offset-2 {
+ margin-left:16.66667%
+}
+.offset-3 {
+ margin-left:25%
+}
+.offset-4 {
+ margin-left:33.33333%
+}
+.offset-5 {
+ margin-left:41.66667%
+}
+.offset-6 {
+ margin-left:50%
+}
+.offset-7 {
+ margin-left:58.33333%
+}
+.offset-8 {
+ margin-left:66.66667%
+}
+.offset-9 {
+ margin-left:75%
+}
+.offset-10 {
+ margin-left:83.33333%
+}
+.offset-11 {
+ margin-left:91.66667%
+}
+@media (min-width:576px) {
+ .col-sm {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-sm-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-sm-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-sm-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-sm-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-sm-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-sm-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-sm-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-sm-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-sm-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-sm-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-sm-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-sm-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-sm-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-sm-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-sm-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-sm-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-sm-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-sm-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-sm-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-sm-first {
+  order:-1
+ }
+ .order-sm-last {
+  order:13
+ }
+ .order-sm-0 {
+  order:0
+ }
+ .order-sm-1 {
+  order:1
+ }
+ .order-sm-2 {
+  order:2
+ }
+ .order-sm-3 {
+  order:3
+ }
+ .order-sm-4 {
+  order:4
+ }
+ .order-sm-5 {
+  order:5
+ }
+ .order-sm-6 {
+  order:6
+ }
+ .order-sm-7 {
+  order:7
+ }
+ .order-sm-8 {
+  order:8
+ }
+ .order-sm-9 {
+  order:9
+ }
+ .order-sm-10 {
+  order:10
+ }
+ .order-sm-11 {
+  order:11
+ }
+ .order-sm-12 {
+  order:12
+ }
+ .offset-sm-0 {
+  margin-left:0
+ }
+ .offset-sm-1 {
+  margin-left:8.33333%
+ }
+ .offset-sm-2 {
+  margin-left:16.66667%
+ }
+ .offset-sm-3 {
+  margin-left:25%
+ }
+ .offset-sm-4 {
+  margin-left:33.33333%
+ }
+ .offset-sm-5 {
+  margin-left:41.66667%
+ }
+ .offset-sm-6 {
+  margin-left:50%
+ }
+ .offset-sm-7 {
+  margin-left:58.33333%
+ }
+ .offset-sm-8 {
+  margin-left:66.66667%
+ }
+ .offset-sm-9 {
+  margin-left:75%
+ }
+ .offset-sm-10 {
+  margin-left:83.33333%
+ }
+ .offset-sm-11 {
+  margin-left:91.66667%
+ }
+}
+@media (min-width:768px) {
+ .col-md {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-md-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-md-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-md-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-md-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-md-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-md-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-md-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-md-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-md-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-md-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-md-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-md-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-md-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-md-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-md-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-md-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-md-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-md-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-md-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-md-first {
+  order:-1
+ }
+ .order-md-last {
+  order:13
+ }
+ .order-md-0 {
+  order:0
+ }
+ .order-md-1 {
+  order:1
+ }
+ .order-md-2 {
+  order:2
+ }
+ .order-md-3 {
+  order:3
+ }
+ .order-md-4 {
+  order:4
+ }
+ .order-md-5 {
+  order:5
+ }
+ .order-md-6 {
+  order:6
+ }
+ .order-md-7 {
+  order:7
+ }
+ .order-md-8 {
+  order:8
+ }
+ .order-md-9 {
+  order:9
+ }
+ .order-md-10 {
+  order:10
+ }
+ .order-md-11 {
+  order:11
+ }
+ .order-md-12 {
+  order:12
+ }
+ .offset-md-0 {
+  margin-left:0
+ }
+ .offset-md-1 {
+  margin-left:8.33333%
+ }
+ .offset-md-2 {
+  margin-left:16.66667%
+ }
+ .offset-md-3 {
+  margin-left:25%
+ }
+ .offset-md-4 {
+  margin-left:33.33333%
+ }
+ .offset-md-5 {
+  margin-left:41.66667%
+ }
+ .offset-md-6 {
+  margin-left:50%
+ }
+ .offset-md-7 {
+  margin-left:58.33333%
+ }
+ .offset-md-8 {
+  margin-left:66.66667%
+ }
+ .offset-md-9 {
+  margin-left:75%
+ }
+ .offset-md-10 {
+  margin-left:83.33333%
+ }
+ .offset-md-11 {
+  margin-left:91.66667%
+ }
+}
+@media (min-width:992px) {
+ .col-lg {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-lg-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-lg-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-lg-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-lg-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-lg-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-lg-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-lg-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-lg-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-lg-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-lg-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-lg-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-lg-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-lg-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-lg-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-lg-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-lg-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-lg-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-lg-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-lg-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-lg-first {
+  order:-1
+ }
+ .order-lg-last {
+  order:13
+ }
+ .order-lg-0 {
+  order:0
+ }
+ .order-lg-1 {
+  order:1
+ }
+ .order-lg-2 {
+  order:2
+ }
+ .order-lg-3 {
+  order:3
+ }
+ .order-lg-4 {
+  order:4
+ }
+ .order-lg-5 {
+  order:5
+ }
+ .order-lg-6 {
+  order:6
+ }
+ .order-lg-7 {
+  order:7
+ }
+ .order-lg-8 {
+  order:8
+ }
+ .order-lg-9 {
+  order:9
+ }
+ .order-lg-10 {
+  order:10
+ }
+ .order-lg-11 {
+  order:11
+ }
+ .order-lg-12 {
+  order:12
+ }
+ .offset-lg-0 {
+  margin-left:0
+ }
+ .offset-lg-1 {
+  margin-left:8.33333%
+ }
+ .offset-lg-2 {
+  margin-left:16.66667%
+ }
+ .offset-lg-3 {
+  margin-left:25%
+ }
+ .offset-lg-4 {
+  margin-left:33.33333%
+ }
+ .offset-lg-5 {
+  margin-left:41.66667%
+ }
+ .offset-lg-6 {
+  margin-left:50%
+ }
+ .offset-lg-7 {
+  margin-left:58.33333%
+ }
+ .offset-lg-8 {
+  margin-left:66.66667%
+ }
+ .offset-lg-9 {
+  margin-left:75%
+ }
+ .offset-lg-10 {
+  margin-left:83.33333%
+ }
+ .offset-lg-11 {
+  margin-left:91.66667%
+ }
+}
+@media (min-width:1200px) {
+ .col-xl {
+  flex-basis:0;
+  flex-grow:1;
+  min-width:0;
+  max-width:100%
+ }
+ .row-cols-xl-1>* {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .row-cols-xl-2>* {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .row-cols-xl-3>* {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .row-cols-xl-4>* {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .row-cols-xl-5>* {
+  flex:0 0 20%;
+  max-width:20%
+ }
+ .row-cols-xl-6>* {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-xl-auto {
+  flex:0 0 auto;
+  width:auto;
+  max-width:100%
+ }
+ .col-xl-1 {
+  flex:0 0 8.33333%;
+  max-width:8.33333%
+ }
+ .col-xl-2 {
+  flex:0 0 16.66667%;
+  max-width:16.66667%
+ }
+ .col-xl-3 {
+  flex:0 0 25%;
+  max-width:25%
+ }
+ .col-xl-4 {
+  flex:0 0 33.33333%;
+  max-width:33.33333%
+ }
+ .col-xl-5 {
+  flex:0 0 41.66667%;
+  max-width:41.66667%
+ }
+ .col-xl-6 {
+  flex:0 0 50%;
+  max-width:50%
+ }
+ .col-xl-7 {
+  flex:0 0 58.33333%;
+  max-width:58.33333%
+ }
+ .col-xl-8 {
+  flex:0 0 66.66667%;
+  max-width:66.66667%
+ }
+ .col-xl-9 {
+  flex:0 0 75%;
+  max-width:75%
+ }
+ .col-xl-10 {
+  flex:0 0 83.33333%;
+  max-width:83.33333%
+ }
+ .col-xl-11 {
+  flex:0 0 91.66667%;
+  max-width:91.66667%
+ }
+ .col-xl-12 {
+  flex:0 0 100%;
+  max-width:100%
+ }
+ .order-xl-first {
+  order:-1
+ }
+ .order-xl-last {
+  order:13
+ }
+ .order-xl-0 {
+  order:0
+ }
+ .order-xl-1 {
+  order:1
+ }
+ .order-xl-2 {
+  order:2
+ }
+ .order-xl-3 {
+  order:3
+ }
+ .order-xl-4 {
+  order:4
+ }
+ .order-xl-5 {
+  order:5
+ }
+ .order-xl-6 {
+  order:6
+ }
+ .order-xl-7 {
+  order:7
+ }
+ .order-xl-8 {
+  order:8
+ }
+ .order-xl-9 {
+  order:9
+ }
+ .order-xl-10 {
+  order:10
+ }
+ .order-xl-11 {
+  order:11
+ }
+ .order-xl-12 {
+  order:12
+ }
+ .offset-xl-0 {
+  margin-left:0
+ }
+ .offset-xl-1 {
+  margin-left:8.33333%
+ }
+ .offset-xl-2 {
+  margin-left:16.66667%
+ }
+ .offset-xl-3 {
+  margin-left:25%
+ }
+ .offset-xl-4 {
+  margin-left:33.33333%
+ }
+ .offset-xl-5 {
+  margin-left:41.66667%
+ }
+ .offset-xl-6 {
+  margin-left:50%
+ }
+ .offset-xl-7 {
+  margin-left:58.33333%
+ }
+ .offset-xl-8 {
+  margin-left:66.66667%
+ }
+ .offset-xl-9 {
+  margin-left:75%
+ }
+ .offset-xl-10 {
+  margin-left:83.33333%
+ }
+ .offset-xl-11 {
+  margin-left:91.66667%
+ }
+}
+.table {
+ width:100%;
+ margin-bottom:1rem;
+ color:#495057
+}
+.table td,
+.table th {
+ padding:.75rem;
+ vertical-align:top;
+ border-top:1px solid #495057
+}
+.table thead th {
+ vertical-align:bottom;
+ border-bottom:2px solid #495057
+}
+.table tbody+tbody {
+ border-top:2px solid #495057
+}
+.table-sm td,
+.table-sm th {
+ padding:.3rem
+}
+.table-bordered {
+ border:1px solid #495057
+}
+.table-bordered td,
+.table-bordered th {
+ border:1px solid #495057
+}
+.table-bordered thead td,
+.table-bordered thead th {
+ border-bottom-width:2px
+}
+.table-borderless tbody+tbody,
+.table-borderless td,
+.table-borderless th,
+.table-borderless thead th {
+ border:0
+}
+.table-striped tbody tr:nth-of-type(odd) {
+ background-color:rgba(34,34,34,.05)
+}
+.table-hover tbody tr:hover {
+ color:#495057;
+ background-color:rgba(34,34,34,.075)
+}
+.table-primary,
+.table-primary>td,
+.table-primary>th {
+ background-color:#fbd4c0
+}
+.table-primary tbody+tbody,
+.table-primary td,
+.table-primary th,
+.table-primary thead th {
+ border-color:#f8ae8a
+}
+.table-hover .table-primary:hover {
+ background-color:#f9c4a8
+}
+.table-hover .table-primary:hover>td,
+.table-hover .table-primary:hover>th {
+ background-color:#f9c4a8
+}
+.table-secondary,
+.table-secondary>td,
+.table-secondary>th {
+ background-color:#b8f0cf
+}
+.table-secondary tbody+tbody,
+.table-secondary td,
+.table-secondary th,
+.table-secondary thead th {
+ border-color:#7ae2a6
+}
+.table-hover .table-secondary:hover {
+ background-color:#a3ecc1
+}
+.table-hover .table-secondary:hover>td,
+.table-hover .table-secondary:hover>th {
+ background-color:#a3ecc1
+}
+.table-success,
+.table-success>td,
+.table-success>th {
+ background-color:#d4bcfb
+}
+.table-success tbody+tbody,
+.table-success td,
+.table-success th,
+.table-success thead th {
+ border-color:#af83f8
+}
+.table-hover .table-success:hover {
+ background-color:#c5a4fa
+}
+.table-hover .table-success:hover>td,
+.table-hover .table-success:hover>th {
+ background-color:#c5a4fa
+}
+.table-info,
+.table-info>td,
+.table-info>th {
+ background-color:#b8daff
+}
+.table-info tbody+tbody,
+.table-info td,
+.table-info th,
+.table-info thead th {
+ border-color:#7abaff
+}
+.table-hover .table-info:hover {
+ background-color:#9fcdff
+}
+.table-hover .table-info:hover>td,
+.table-hover .table-info:hover>th {
+ background-color:#9fcdff
+}
+.table-warning,
+.table-warning>td,
+.table-warning>th {
+ background-color:#ffeeba
+}
+.table-warning tbody+tbody,
+.table-warning td,
+.table-warning th,
+.table-warning thead th {
+ border-color:#ffdf7e
+}
+.table-hover .table-warning:hover {
+ background-color:#ffe8a1
+}
+.table-hover .table-warning:hover>td,
+.table-hover .table-warning:hover>th {
+ background-color:#ffe8a1
+}
+.table-danger,
+.table-danger>td,
+.table-danger>th {
+ background-color:#ddc6ba
+}
+.table-danger tbody+tbody,
+.table-danger td,
+.table-danger th,
+.table-danger thead th {
+ border-color:#c1957f
+}
+.table-hover .table-danger:hover {
+ background-color:#d5b8a9
+}
+.table-hover .table-danger:hover>td,
+.table-hover .table-danger:hover>th {
+ background-color:#d5b8a9
+}
+.table-light,
+.table-light>td,
+.table-light>th {
+ background-color:#fdfdfe
+}
+.table-light tbody+tbody,
+.table-light td,
+.table-light th,
+.table-light thead th {
+ border-color:#fbfcfc
+}
+.table-hover .table-light:hover {
+ background-color:#ececf6
+}
+.table-hover .table-light:hover>td,
+.table-hover .table-light:hover>th {
+ background-color:#ececf6
+}
+.table-dark,
+.table-dark>td,
+.table-dark>th {
+ background-color:#c6c8ca
+}
+.table-dark tbody+tbody,
+.table-dark td,
+.table-dark th,
+.table-dark thead th {
+ border-color:#95999c
+}
+.table-hover .table-dark:hover {
+ background-color:#b9bbbe
+}
+.table-hover .table-dark:hover>td,
+.table-hover .table-dark:hover>th {
+ background-color:#b9bbbe
+}
+.table-active,
+.table-active>td,
+.table-active>th {
+ background-color:rgba(34,34,34,.075)
+}
+.table-hover .table-active:hover {
+ background-color:rgba(21,21,21,.075)
+}
+.table-hover .table-active:hover>td,
+.table-hover .table-active:hover>th {
+ background-color:rgba(21,21,21,.075)
+}
+.table .thead-dark th {
+ color:#fff;
+ background-color:#343a40;
+ border-color:#454d55
+}
+.table .thead-light th {
+ color:#495057;
+ background-color:#e9ecef;
+ border-color:#495057
+}
+.table-dark {
+ color:#fff;
+ background-color:#343a40
+}
+.table-dark td,
+.table-dark th,
+.table-dark thead th {
+ border-color:#454d55
+}
+.table-dark.table-bordered {
+ border:0
+}
+.table-dark.table-striped tbody tr:nth-of-type(odd) {
+ background-color:rgba(255,255,255,.05)
+}
+.table-dark.table-hover tbody tr:hover {
+ color:#fff;
+ background-color:rgba(255,255,255,.075)
+}
+@media (max-width:575.98px) {
+ .table-responsive-sm {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-sm>.table-bordered {
+  border:0
+ }
+}
+@media (max-width:767.98px) {
+ .table-responsive-md {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-md>.table-bordered {
+  border:0
+ }
+}
+@media (max-width:991.98px) {
+ .table-responsive-lg {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-lg>.table-bordered {
+  border:0
+ }
+}
+@media (max-width:1199.98px) {
+ .table-responsive-xl {
+  display:block;
+  width:100%;
+  overflow-x:auto;
+  -webkit-overflow-scrolling:touch
+ }
+ .table-responsive-xl>.table-bordered {
+  border:0
+ }
+}
+.table-responsive {
+ display:block;
+ width:100%;
+ overflow-x:auto;
+ -webkit-overflow-scrolling:touch
+}
+.table-responsive>.table-bordered {
+ border:0
+}
+.form-control {
+ display:block;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ padding:.375rem .75rem;
+ font-size:1rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#495057;
+ background-color:#fff;
+ background-clip:padding-box;
+ border:1px solid #ced4da;
+ border-radius:.5rem;
+ transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .form-control {
+  transition:none
+ }
+}
+.form-control::-ms-expand {
+ background-color:transparent;
+ border:0
+}
+.form-control:-moz-focusring {
+ color:transparent;
+ text-shadow:0 0 0 #495057
+}
+.form-control:focus {
+ color:#495057;
+ background-color:#fff;
+ border-color:#f89696;
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(241, 30, 30, 0.75);
+}
+.form-control::placeholder {
+ color:#6c757d;
+ opacity:1
+}
+.form-control:disabled,
+.form-control[readonly] {
+ background-color:#e9ecef;
+ opacity:1
+}
+input[type=date].form-control,
+input[type=datetime-local].form-control,
+input[type=month].form-control,
+input[type=time].form-control {
+ appearance:none
+}
+select.form-control:focus::-ms-value {
+ color:#495057;
+ background-color:#fff
+}
+.form-control-file,
+.form-control-range {
+ display:block;
+ width:100%
+}
+.col-form-label {
+ padding-top:calc(.375rem + 1px);
+ padding-bottom:calc(.375rem + 1px);
+ margin-bottom:0;
+ font-size:inherit;
+ line-height:1.5
+}
+.col-form-label-lg {
+ padding-top:calc(.5rem + 1px);
+ padding-bottom:calc(.5rem + 1px);
+ font-size:1.25rem;
+ line-height:1.5
+}
+.col-form-label-sm {
+ padding-top:calc(.25rem + 1px);
+ padding-bottom:calc(.25rem + 1px);
+ font-size:.875rem;
+ line-height:1.5
+}
+.form-control-plaintext {
+ display:block;
+ width:100%;
+ padding:.375rem 0;
+ margin-bottom:0;
+ font-size:1rem;
+ line-height:1.5;
+ color:#495057;
+ background-color:transparent;
+ border:solid transparent;
+ border-width:1px 0
+}
+.form-control-plaintext.form-control-lg,
+.form-control-plaintext.form-control-sm {
+ padding-right:0;
+ padding-left:0
+}
+.form-control-sm {
+ height:calc(1.5em + .5rem + 2px);
+ padding:.25rem .5rem;
+ font-size:.875rem;
+ line-height:1.5;
+ border-radius:1rem
+}
+.form-control-lg {
+ height:calc(1.5em + 1rem + 2px);
+ padding:.5rem 1rem;
+ font-size:1.25rem;
+ line-height:1.5;
+ border-radius:.5rem
+}
+select.form-control[multiple],
+select.form-control[size] {
+ height:auto
+}
+textarea.form-control {
+ height:auto
+}
+.form-group {
+ margin-bottom:1rem
+}
+.form-text {
+ display:block;
+ margin-top:.25rem
+}
+.form-row {
+ display:flex;
+ flex-wrap:wrap;
+ margin-right:-5px;
+ margin-left:-5px
+}
+.form-row>.col,
+.form-row>[class*=col-] {
+ padding-right:5px;
+ padding-left:5px
+}
+.form-check {
+ position:relative;
+ display:block;
+ padding-left:1.25rem
+}
+.form-check-input {
+ position:absolute;
+ margin-top:.3rem;
+ margin-left:-1.25rem
+}
+.form-check-input:disabled~.form-check-label,
+.form-check-input[disabled]~.form-check-label {
+ color:#6c757d
+}
+.form-check-label {
+ margin-bottom:0
+}
+.form-check-inline {
+ display:inline-flex;
+ align-items:center;
+ padding-left:0;
+ margin-right:.75rem
+}
+.form-check-inline .form-check-input {
+ position:static;
+ margin-top:0;
+ margin-right:.3125rem;
+ margin-left:0
+}
+.valid-feedback {
+ display:none;
+ width:100%;
+ margin-top:.25rem;
+ font-size:80%;
+ color:#007bff
+}
+.valid-tooltip {
+ position:absolute;
+ top:100%;
+ z-index:5;
+ display:none;
+ max-width:100%;
+ padding:.25rem .5rem;
+ margin-top:.1rem;
+ font-size:.875rem;
+ line-height:1.5;
+ color:#fff;
+ background-color:rgba(0,123,255,.9);
+ border-radius:.5rem
+}
+.is-valid~.valid-feedback,
+.is-valid~.valid-tooltip,
+.was-validated :valid~.valid-feedback,
+.was-validated :valid~.valid-tooltip {
+ display:block
+}
+.form-control.is-valid,
+.was-validated .form-control:valid {
+ border-color:#007bff;
+ padding-right:calc(1.5em + .75rem);
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23007bff' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");
+ background-repeat:no-repeat;
+ background-position:right calc(.375em + .1875rem) center;
+ background-size:calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.form-control.is-valid:focus,
+.was-validated .form-control:valid:focus {
+ border-color:#007bff;
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.25)
+}
+.was-validated textarea.form-control:valid,
+textarea.form-control.is-valid {
+ padding-right:calc(1.5em + .75rem);
+ background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)
+}
+.custom-select.is-valid,
+.was-validated .custom-select:valid {
+ border-color:#007bff;
+ padding-right:calc(.75em + 2.3125rem);
+ background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23007bff' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.custom-select.is-valid:focus,
+.was-validated .custom-select:valid:focus {
+ border-color:#007bff;
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.25)
+}
+.form-check-input.is-valid~.form-check-label,
+.was-validated .form-check-input:valid~.form-check-label {
+ color:#007bff
+}
+.form-check-input.is-valid~.valid-feedback,
+.form-check-input.is-valid~.valid-tooltip,
+.was-validated .form-check-input:valid~.valid-feedback,
+.was-validated .form-check-input:valid~.valid-tooltip {
+ display:block
+}
+.custom-control-input.is-valid~.custom-control-label,
+.was-validated .custom-control-input:valid~.custom-control-label {
+ color:#007bff
+}
+.custom-control-input.is-valid~.custom-control-label::before,
+.was-validated .custom-control-input:valid~.custom-control-label::before {
+ border-color:#007bff
+}
+.custom-control-input.is-valid:checked~.custom-control-label::before,
+.was-validated .custom-control-input:valid:checked~.custom-control-label::before {
+ border-color:#3395ff;
+ background-color:#3395ff
+}
+.custom-control-input.is-valid:focus~.custom-control-label::before,
+.was-validated .custom-control-input:valid:focus~.custom-control-label::before {
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.25)
+}
+.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,
+.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before {
+ border-color:#007bff
+}
+.custom-file-input.is-valid~.custom-file-label,
+.was-validated .custom-file-input:valid~.custom-file-label {
+ border-color:#007bff
+}
+.custom-file-input.is-valid:focus~.custom-file-label,
+.was-validated .custom-file-input:valid:focus~.custom-file-label {
+ border-color:#007bff;
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.25)
+}
+.invalid-feedback {
+ display:none;
+ width:100%;
+ margin-top:.25rem;
+ font-size:80%;
+ color:#873208
+}
+.invalid-tooltip {
+ position:absolute;
+ top:100%;
+ z-index:5;
+ display:none;
+ max-width:100%;
+ padding:.25rem .5rem;
+ margin-top:.1rem;
+ font-size:.875rem;
+ line-height:1.5;
+ color:#fff;
+ background-color:rgba(135,50,8,.9);
+ border-radius:.5rem
+}
+.is-invalid~.invalid-feedback,
+.is-invalid~.invalid-tooltip,
+.was-validated :invalid~.invalid-feedback,
+.was-validated :invalid~.invalid-tooltip {
+ display:block
+}
+.form-control.is-invalid,
+.was-validated .form-control:invalid {
+ border-color:#873208;
+ padding-right:calc(1.5em + .75rem);
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23873208' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23873208' stroke='none'/%3e%3c/svg%3e");
+ background-repeat:no-repeat;
+ background-position:right calc(.375em + .1875rem) center;
+ background-size:calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.form-control.is-invalid:focus,
+.was-validated .form-control:invalid:focus {
+ border-color:#873208;
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.25)
+}
+.was-validated textarea.form-control:invalid,
+textarea.form-control.is-invalid {
+ padding-right:calc(1.5em + .75rem);
+ background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)
+}
+.custom-select.is-invalid,
+.was-validated .custom-select:invalid {
+ border-color:#873208;
+ padding-right:calc(.75em + 2.3125rem);
+ background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23873208' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23873208' stroke='none'/%3e%3c/svg%3e") #fff no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)
+}
+.custom-select.is-invalid:focus,
+.was-validated .custom-select:invalid:focus {
+ border-color:#873208;
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.25)
+}
+.form-check-input.is-invalid~.form-check-label,
+.was-validated .form-check-input:invalid~.form-check-label {
+ color:#873208
+}
+.form-check-input.is-invalid~.invalid-feedback,
+.form-check-input.is-invalid~.invalid-tooltip,
+.was-validated .form-check-input:invalid~.invalid-feedback,
+.was-validated .form-check-input:invalid~.invalid-tooltip {
+ display:block
+}
+.custom-control-input.is-invalid~.custom-control-label,
+.was-validated .custom-control-input:invalid~.custom-control-label {
+ color:#873208
+}
+.custom-control-input.is-invalid~.custom-control-label::before,
+.was-validated .custom-control-input:invalid~.custom-control-label::before {
+ border-color:#873208
+}
+.custom-control-input.is-invalid:checked~.custom-control-label::before,
+.was-validated .custom-control-input:invalid:checked~.custom-control-label::before {
+ border-color:#b7440b;
+ background-color:#b7440b
+}
+.custom-control-input.is-invalid:focus~.custom-control-label::before,
+.was-validated .custom-control-input:invalid:focus~.custom-control-label::before {
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.25)
+}
+.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,
+.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before {
+ border-color:#873208
+}
+.custom-file-input.is-invalid~.custom-file-label,
+.was-validated .custom-file-input:invalid~.custom-file-label {
+ border-color:#873208
+}
+.custom-file-input.is-invalid:focus~.custom-file-label,
+.was-validated .custom-file-input:invalid:focus~.custom-file-label {
+ border-color:#873208;
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.25)
+}
+.form-inline {
+ display:flex;
+ flex-flow:row wrap;
+ align-items:center
+}
+.form-inline .form-check {
+ width:100%
+}
+@media (min-width:576px) {
+ .form-inline label {
+  display:flex;
+  align-items:center;
+  justify-content:center;
+  margin-bottom:0
+ }
+ .form-inline .form-group {
+  display:flex;
+  flex:0 0 auto;
+  flex-flow:row wrap;
+  align-items:center;
+  margin-bottom:0
+ }
+ .form-inline .form-control {
+  display:inline-block;
+  width:auto;
+  vertical-align:middle
+ }
+ .form-inline .form-control-plaintext {
+  display:inline-block
+ }
+ .form-inline .custom-select,
+ .form-inline .input-group {
+  width:auto
+ }
+ .form-inline .form-check {
+  display:flex;
+  align-items:center;
+  justify-content:center;
+  width:auto;
+  padding-left:0
+ }
+ .form-inline .form-check-input {
+  position:relative;
+  flex-shrink:0;
+  margin-top:0;
+  margin-right:.25rem;
+  margin-left:0
+ }
+ .form-inline .custom-control {
+  align-items:center;
+  justify-content:center
+ }
+ .form-inline .custom-control-label {
+  margin-bottom:0
+ }
+}
+.btn {
+ display:inline-block;
+ font-weight:400;
+ color:#495057;
+ text-align:center;
+ vertical-align:middle;
+ user-select:none;
+ background-color:transparent;
+ border:1px solid transparent;
+ padding:.375rem .75rem;
+ font-size:1rem;
+ line-height:1.5;
+ border-radius:.5rem;
+ transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .btn {
+  transition:none
+ }
+}
+.btn:hover {
+ color:#495057;
+ text-decoration:none
+}
+.btn.focus,
+.btn:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(241, 30, 30, 0.75);
+}
+.btn.disabled,
+.btn:disabled {
+ opacity:.65
+}
+.btn:not(:disabled):not(.disabled) {
+ cursor:pointer
+}
+a.btn.disabled,
+fieldset:disabled a.btn {
+ pointer-events:none
+}
+.btn-primary {
+ color:#fff;
+ background-color:#f1641e;
+ border-color:#f1641e
+}
+.btn-primary:hover {
+ color:#fff;
+ background-color:#db520e;
+ border-color:#cf4d0d
+}
+.btn-primary.focus,
+.btn-primary:focus {
+ color:#fff;
+ background-color:#db520e;
+ border-color:#cf4d0d;
+ box-shadow:0 0 0 .2rem rgba(243,123,64,.5)
+}
+.btn-primary.disabled,
+.btn-primary:disabled {
+ color:#fff;
+ background-color:#f1641e;
+ border-color:#f1641e
+}
+.btn-primary:not(:disabled):not(.disabled).active,
+.btn-primary:not(:disabled):not(.disabled):active,
+.show>.btn-primary.dropdown-toggle {
+ color:#fff;
+ background-color:#cf4d0d;
+ border-color:#c3490c
+}
+.btn-primary:not(:disabled):not(.disabled).active:focus,
+.btn-primary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-primary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(243,123,64,.5)
+}
+.btn-secondary {
+ color:#fff;
+ background-color:#c80000;
+ border-color:#c80000;
+}
+.btn-secondary:hover {
+ color:#fff;
+ background-color:#a20000;
+ border-color:#950000;
+}
+.btn-secondary.focus,
+.btn-secondary:focus {
+ color:#fff;
+ background-color:#00a243;
+ border-color:#00953e;
+ box-shadow:0 0 0 .2rem rgba(38,208,109,.5)
+}
+.btn-secondary.disabled,
+.btn-secondary:disabled {
+ color:#fff;
+ background-color:#c80000;
+ border-color:#c80000;
+}
+.btn-secondary:not(:disabled):not(.disabled).active,
+.btn-secondary:not(:disabled):not(.disabled):active,
+.show>.btn-secondary.dropdown-toggle {
+ color:#fff;
+ background-color:#00953e;
+ border-color:#008839
+}
+.btn-secondary:not(:disabled):not(.disabled).active:focus,
+.btn-secondary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-secondary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(38,208,109,.5)
+}
+.btn-success {
+ color:#fff;
+ background-color:#6610f2;
+ border-color:#6610f2
+}
+.btn-success:hover {
+ color:#fff;
+ background-color:#560bd0;
+ border-color:#510bc4
+}
+.btn-success.focus,
+.btn-success:focus {
+ color:#fff;
+ background-color:#560bd0;
+ border-color:#510bc4;
+ box-shadow:0 0 0 .2rem rgba(125,52,244,.5)
+}
+.btn-success.disabled,
+.btn-success:disabled {
+ color:#fff;
+ background-color:#6610f2;
+ border-color:#6610f2
+}
+.btn-success:not(:disabled):not(.disabled).active,
+.btn-success:not(:disabled):not(.disabled):active,
+.show>.btn-success.dropdown-toggle {
+ color:#fff;
+ background-color:#510bc4;
+ border-color:#4c0ab8
+}
+.btn-success:not(:disabled):not(.disabled).active:focus,
+.btn-success:not(:disabled):not(.disabled):active:focus,
+.show>.btn-success.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(125,52,244,.5)
+}
+.btn-info {
+ color:#fff;
+ background-color:#007bff;
+ border-color:#007bff
+}
+.btn-info:hover {
+ color:#fff;
+ background-color:#0069d9;
+ border-color:#0062cc
+}
+.btn-info.focus,
+.btn-info:focus {
+ color:#fff;
+ background-color:#0069d9;
+ border-color:#0062cc;
+ box-shadow:0 0 0 .2rem rgba(38,143,255,.5)
+}
+.btn-info.disabled,
+.btn-info:disabled {
+ color:#fff;
+ background-color:#007bff;
+ border-color:#007bff
+}
+.btn-info:not(:disabled):not(.disabled).active,
+.btn-info:not(:disabled):not(.disabled):active,
+.show>.btn-info.dropdown-toggle {
+ color:#fff;
+ background-color:#0062cc;
+ border-color:#005cbf
+}
+.btn-info:not(:disabled):not(.disabled).active:focus,
+.btn-info:not(:disabled):not(.disabled):active:focus,
+.show>.btn-info.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(38,143,255,.5)
+}
+.btn-warning {
+ color:#212529;
+ background-color:#ffc107;
+ border-color:#ffc107
+}
+.btn-warning:hover {
+ color:#212529;
+ background-color:#e0a800;
+ border-color:#d39e00
+}
+.btn-warning.focus,
+.btn-warning:focus {
+ color:#212529;
+ background-color:#e0a800;
+ border-color:#d39e00;
+ box-shadow:0 0 0 .2rem rgba(222,170,12,.5)
+}
+.btn-warning.disabled,
+.btn-warning:disabled {
+ color:#212529;
+ background-color:#ffc107;
+ border-color:#ffc107
+}
+.btn-warning:not(:disabled):not(.disabled).active,
+.btn-warning:not(:disabled):not(.disabled):active,
+.show>.btn-warning.dropdown-toggle {
+ color:#212529;
+ background-color:#d39e00;
+ border-color:#c69500
+}
+.btn-warning:not(:disabled):not(.disabled).active:focus,
+.btn-warning:not(:disabled):not(.disabled):active:focus,
+.show>.btn-warning.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(222,170,12,.5)
+}
+.btn-danger {
+ color:#fff;
+ background-color:#873208;
+ border-color:#873208
+}
+.btn-danger:hover {
+ color:#fff;
+ background-color:#632506;
+ border-color:#572105
+}
+.btn-danger.focus,
+.btn-danger:focus {
+ color:#fff;
+ background-color:#632506;
+ border-color:#572105;
+ box-shadow:0 0 0 .2rem rgba(153,81,45,.5)
+}
+.btn-danger.disabled,
+.btn-danger:disabled {
+ color:#fff;
+ background-color:#873208;
+ border-color:#873208
+}
+.btn-danger:not(:disabled):not(.disabled).active,
+.btn-danger:not(:disabled):not(.disabled):active,
+.show>.btn-danger.dropdown-toggle {
+ color:#fff;
+ background-color:#572105;
+ border-color:#4b1c05
+}
+.btn-danger:not(:disabled):not(.disabled).active:focus,
+.btn-danger:not(:disabled):not(.disabled):active:focus,
+.show>.btn-danger.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(153,81,45,.5)
+}
+.btn-light {
+ color:#212529;
+ background-color:#f8f9fa;
+ border-color:#f8f9fa
+}
+.btn-light:hover {
+ color:#212529;
+ background-color:#e2e6ea;
+ border-color:#dae0e5
+}
+.btn-light.focus,
+.btn-light:focus {
+ color:#212529;
+ background-color:#e2e6ea;
+ border-color:#dae0e5;
+ box-shadow:0 0 0 .2rem rgba(216,217,219,.5)
+}
+.btn-light.disabled,
+.btn-light:disabled {
+ color:#212529;
+ background-color:#f8f9fa;
+ border-color:#f8f9fa
+}
+.btn-light:not(:disabled):not(.disabled).active,
+.btn-light:not(:disabled):not(.disabled):active,
+.show>.btn-light.dropdown-toggle {
+ color:#212529;
+ background-color:#dae0e5;
+ border-color:#d3d9df
+}
+.btn-light:not(:disabled):not(.disabled).active:focus,
+.btn-light:not(:disabled):not(.disabled):active:focus,
+.show>.btn-light.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(216,217,219,.5)
+}
+.btn-dark {
+ color:#fff;
+ background-color:#343a40;
+ border-color:#343a40
+}
+.btn-dark:hover {
+ color:#fff;
+ background-color:#23272b;
+ border-color:#1d2124
+}
+.btn-dark.focus,
+.btn-dark:focus {
+ color:#fff;
+ background-color:#23272b;
+ border-color:#1d2124;
+ box-shadow:0 0 0 .2rem rgba(82,88,93,.5)
+}
+.btn-dark.disabled,
+.btn-dark:disabled {
+ color:#fff;
+ background-color:#343a40;
+ border-color:#343a40
+}
+.btn-dark:not(:disabled):not(.disabled).active,
+.btn-dark:not(:disabled):not(.disabled):active,
+.show>.btn-dark.dropdown-toggle {
+ color:#fff;
+ background-color:#1d2124;
+ border-color:#171a1d
+}
+.btn-dark:not(:disabled):not(.disabled).active:focus,
+.btn-dark:not(:disabled):not(.disabled):active:focus,
+.show>.btn-dark.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(82,88,93,.5)
+}
+.btn-outline-primary {
+ color:#f1641e;
+ border-color:#f1641e
+}
+.btn-outline-primary:hover {
+ color:#fff;
+ background-color:#f1641e;
+ border-color:#f1641e
+}
+.btn-outline-primary.focus,
+.btn-outline-primary:focus {
+ box-shadow:0 0 0 .2rem rgba(241,100,30,.5)
+}
+.btn-outline-primary.disabled,
+.btn-outline-primary:disabled {
+ color:#f1641e;
+ background-color:transparent
+}
+.btn-outline-primary:not(:disabled):not(.disabled).active,
+.btn-outline-primary:not(:disabled):not(.disabled):active,
+.show>.btn-outline-primary.dropdown-toggle {
+ color:#fff;
+ background-color:#f1641e;
+ border-color:#f1641e
+}
+.btn-outline-primary:not(:disabled):not(.disabled).active:focus,
+.btn-outline-primary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-primary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(241,100,30,.5)
+}
+.btn-outline-secondary {
+ color:#c80000;
+ border-color:#c80000;
+}
+.btn-outline-secondary:hover {
+ color:#fff;
+ background-color:#c80000;
+ border-color:#c80000;
+}
+.btn-outline-secondary.focus,
+.btn-outline-secondary:focus {
+ box-shadow:0 0 0 .2rem rgba(0,200,83,.5)
+}
+.btn-outline-secondary.disabled,
+.btn-outline-secondary:disabled {
+ color:#c80000;
+ background-color:transparent
+}
+.btn-outline-secondary:not(:disabled):not(.disabled).active,
+.btn-outline-secondary:not(:disabled):not(.disabled):active,
+.show>.btn-outline-secondary.dropdown-toggle {
+ color:#fff;
+ background-color:#c80000;
+ border-color:#c80000;
+}
+.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,
+.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-secondary.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(0,200,83,.5)
+}
+.btn-outline-success {
+ color:#6610f2;
+ border-color:#6610f2
+}
+.btn-outline-success:hover {
+ color:#fff;
+ background-color:#6610f2;
+ border-color:#6610f2
+}
+.btn-outline-success.focus,
+.btn-outline-success:focus {
+ box-shadow:0 0 0 .2rem rgba(102,16,242,.5)
+}
+.btn-outline-success.disabled,
+.btn-outline-success:disabled {
+ color:#6610f2;
+ background-color:transparent
+}
+.btn-outline-success:not(:disabled):not(.disabled).active,
+.btn-outline-success:not(:disabled):not(.disabled):active,
+.show>.btn-outline-success.dropdown-toggle {
+ color:#fff;
+ background-color:#6610f2;
+ border-color:#6610f2
+}
+.btn-outline-success:not(:disabled):not(.disabled).active:focus,
+.btn-outline-success:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-success.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(102,16,242,.5)
+}
+.btn-outline-info {
+ color:#007bff;
+ border-color:#007bff
+}
+.btn-outline-info:hover {
+ color:#fff;
+ background-color:#007bff;
+ border-color:#007bff
+}
+.btn-outline-info.focus,
+.btn-outline-info:focus {
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.5)
+}
+.btn-outline-info.disabled,
+.btn-outline-info:disabled {
+ color:#007bff;
+ background-color:transparent
+}
+.btn-outline-info:not(:disabled):not(.disabled).active,
+.btn-outline-info:not(:disabled):not(.disabled):active,
+.show>.btn-outline-info.dropdown-toggle {
+ color:#fff;
+ background-color:#007bff;
+ border-color:#007bff
+}
+.btn-outline-info:not(:disabled):not(.disabled).active:focus,
+.btn-outline-info:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-info.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.5)
+}
+.btn-outline-warning {
+ color:#ffc107;
+ border-color:#ffc107
+}
+.btn-outline-warning:hover {
+ color:#212529;
+ background-color:#ffc107;
+ border-color:#ffc107
+}
+.btn-outline-warning.focus,
+.btn-outline-warning:focus {
+ box-shadow:0 0 0 .2rem rgba(255,193,7,.5)
+}
+.btn-outline-warning.disabled,
+.btn-outline-warning:disabled {
+ color:#ffc107;
+ background-color:transparent
+}
+.btn-outline-warning:not(:disabled):not(.disabled).active,
+.btn-outline-warning:not(:disabled):not(.disabled):active,
+.show>.btn-outline-warning.dropdown-toggle {
+ color:#212529;
+ background-color:#ffc107;
+ border-color:#ffc107
+}
+.btn-outline-warning:not(:disabled):not(.disabled).active:focus,
+.btn-outline-warning:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-warning.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(255,193,7,.5)
+}
+.btn-outline-danger {
+ color:#873208;
+ border-color:#873208
+}
+.btn-outline-danger:hover {
+ color:#fff;
+ background-color:#873208;
+ border-color:#873208
+}
+.btn-outline-danger.focus,
+.btn-outline-danger:focus {
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.5)
+}
+.btn-outline-danger.disabled,
+.btn-outline-danger:disabled {
+ color:#873208;
+ background-color:transparent
+}
+.btn-outline-danger:not(:disabled):not(.disabled).active,
+.btn-outline-danger:not(:disabled):not(.disabled):active,
+.show>.btn-outline-danger.dropdown-toggle {
+ color:#fff;
+ background-color:#873208;
+ border-color:#873208
+}
+.btn-outline-danger:not(:disabled):not(.disabled).active:focus,
+.btn-outline-danger:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-danger.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.5)
+}
+.btn-outline-light {
+ color:#f8f9fa;
+ border-color:#f8f9fa
+}
+.btn-outline-light:hover {
+ color:#212529;
+ background-color:#f8f9fa;
+ border-color:#f8f9fa
+}
+.btn-outline-light.focus,
+.btn-outline-light:focus {
+ box-shadow:0 0 0 .2rem rgba(248,249,250,.5)
+}
+.btn-outline-light.disabled,
+.btn-outline-light:disabled {
+ color:#f8f9fa;
+ background-color:transparent
+}
+.btn-outline-light:not(:disabled):not(.disabled).active,
+.btn-outline-light:not(:disabled):not(.disabled):active,
+.show>.btn-outline-light.dropdown-toggle {
+ color:#212529;
+ background-color:#f8f9fa;
+ border-color:#f8f9fa
+}
+.btn-outline-light:not(:disabled):not(.disabled).active:focus,
+.btn-outline-light:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-light.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(248,249,250,.5)
+}
+.btn-outline-dark {
+ color:#343a40;
+ border-color:#343a40
+}
+.btn-outline-dark:hover {
+ color:#fff;
+ background-color:#343a40;
+ border-color:#343a40
+}
+.btn-outline-dark.focus,
+.btn-outline-dark:focus {
+ box-shadow:0 0 0 .2rem rgba(52,58,64,.5)
+}
+.btn-outline-dark.disabled,
+.btn-outline-dark:disabled {
+ color:#343a40;
+ background-color:transparent
+}
+.btn-outline-dark:not(:disabled):not(.disabled).active,
+.btn-outline-dark:not(:disabled):not(.disabled):active,
+.show>.btn-outline-dark.dropdown-toggle {
+ color:#fff;
+ background-color:#343a40;
+ border-color:#343a40
+}
+.btn-outline-dark:not(:disabled):not(.disabled).active:focus,
+.btn-outline-dark:not(:disabled):not(.disabled):active:focus,
+.show>.btn-outline-dark.dropdown-toggle:focus {
+ box-shadow:0 0 0 .2rem rgba(52,58,64,.5)
+}
+.btn-link {
+ font-weight:400;
+ color:#f1641e;
+ text-decoration:none
+}
+.btn-link:hover {
+ color:#b7440b;
+ text-decoration:underline
+}
+.btn-link.focus,
+.btn-link:focus {
+ text-decoration:underline
+}
+.btn-link.disabled,
+.btn-link:disabled {
+ color:#6c757d;
+ pointer-events:none
+}
+.btn-group-lg>.btn,
+.btn-lg {
+ padding:.5rem 1rem;
+ font-size:1.25rem;
+ line-height:1.5;
+ border-radius:.5rem
+}
+.btn-group-sm>.btn,
+.btn-sm {
+ padding:.25rem .5rem;
+ font-size:.875rem;
+ line-height:1.5;
+ border-radius:1rem
+}
+.btn-block {
+ display:block;
+ width:100%
+}
+.btn-block+.btn-block {
+ margin-top:.5rem
+}
+input[type=button].btn-block,
+input[type=reset].btn-block,
+input[type=submit].btn-block {
+ width:100%
+}
+.fade {
+ transition:opacity .15s linear
+}
+@media (prefers-reduced-motion:reduce) {
+ .fade {
+  transition:none
+ }
+}
+.fade:not(.show) {
+ opacity:0
+}
+.collapse:not(.show) {
+ display:none
+}
+.collapsing {
+ position:relative;
+ height:0;
+ overflow:hidden;
+ transition:height .35s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .collapsing {
+  transition:none
+ }
+}
+.dropdown,
+.dropleft,
+.dropright,
+.dropup {
+ position:relative
+}
+.dropdown-toggle {
+ white-space:nowrap
+}
+.dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:.3em solid;
+ border-right:.3em solid transparent;
+ border-bottom:0;
+ border-left:.3em solid transparent
+}
+.dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropdown-menu {
+ position:absolute;
+ top:100%;
+ left:0;
+ z-index:1000;
+ display:none;
+ float:left;
+ min-width:10rem;
+ padding:.5rem 0;
+ margin:.125rem 0 0;
+ font-size:1rem;
+ color:#495057;
+ text-align:left;
+ list-style:none;
+ background-color:#fff;
+ background-clip:padding-box;
+ border:1px solid rgba(34,34,34,.15);
+ border-radius:.5rem
+}
+.dropdown-menu-left {
+ right:auto;
+ left:0
+}
+.dropdown-menu-right {
+ right:0;
+ left:auto
+}
+@media (min-width:576px) {
+ .dropdown-menu-sm-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-sm-right {
+  right:0;
+  left:auto
+ }
+}
+@media (min-width:768px) {
+ .dropdown-menu-md-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-md-right {
+  right:0;
+  left:auto
+ }
+}
+@media (min-width:992px) {
+ .dropdown-menu-lg-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-lg-right {
+  right:0;
+  left:auto
+ }
+}
+@media (min-width:1200px) {
+ .dropdown-menu-xl-left {
+  right:auto;
+  left:0
+ }
+ .dropdown-menu-xl-right {
+  right:0;
+  left:auto
+ }
+}
+.dropup .dropdown-menu {
+ top:auto;
+ bottom:100%;
+ margin-top:0;
+ margin-bottom:.125rem
+}
+.dropup .dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:0;
+ border-right:.3em solid transparent;
+ border-bottom:.3em solid;
+ border-left:.3em solid transparent
+}
+.dropup .dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropright .dropdown-menu {
+ top:0;
+ right:auto;
+ left:100%;
+ margin-top:0;
+ margin-left:.125rem
+}
+.dropright .dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:.3em solid transparent;
+ border-right:0;
+ border-bottom:.3em solid transparent;
+ border-left:.3em solid
+}
+.dropright .dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropright .dropdown-toggle::after {
+ vertical-align:0
+}
+.dropleft .dropdown-menu {
+ top:0;
+ right:100%;
+ left:auto;
+ margin-top:0;
+ margin-right:.125rem
+}
+.dropleft .dropdown-toggle::after {
+ display:inline-block;
+ margin-left:.255em;
+ vertical-align:.255em;
+ content:""
+}
+.dropleft .dropdown-toggle::after {
+ display:none
+}
+.dropleft .dropdown-toggle::before {
+ display:inline-block;
+ margin-right:.255em;
+ vertical-align:.255em;
+ content:"";
+ border-top:.3em solid transparent;
+ border-right:.3em solid;
+ border-bottom:.3em solid transparent
+}
+.dropleft .dropdown-toggle:empty::after {
+ margin-left:0
+}
+.dropleft .dropdown-toggle::before {
+ vertical-align:0
+}
+.dropdown-menu[x-placement^=bottom],
+.dropdown-menu[x-placement^=left],
+.dropdown-menu[x-placement^=right],
+.dropdown-menu[x-placement^=top] {
+ right:auto;
+ bottom:auto
+}
+.dropdown-divider {
+ height:0;
+ margin:.5rem 0;
+ overflow:hidden;
+ border-top:1px solid #e9ecef
+}
+.dropdown-item {
+ display:block;
+ width:100%;
+ padding:.25rem 1.5rem;
+ clear:both;
+ font-weight:400;
+ color:#212529;
+ text-align:inherit;
+ white-space:nowrap;
+ background-color:transparent;
+ border:0
+}
+.dropdown-item:focus,
+.dropdown-item:hover {
+ color:#16181b;
+ text-decoration:none;
+ background-color:#f8f9fa
+}
+.dropdown-item.active,
+.dropdown-item:active {
+ color:#fff;
+ text-decoration:none;
+ background-color:#f1641e
+}
+.dropdown-item.disabled,
+.dropdown-item:disabled {
+ color:#6c757d;
+ pointer-events:none;
+ background-color:transparent
+}
+.dropdown-menu.show {
+ display:block
+}
+.dropdown-header {
+ display:block;
+ padding:.5rem 1.5rem;
+ margin-bottom:0;
+ font-size:.875rem;
+ color:#6c757d;
+ white-space:nowrap
+}
+.dropdown-item-text {
+ display:block;
+ padding:.25rem 1.5rem;
+ color:#212529
+}
+.btn-group,
+.btn-group-vertical {
+ position:relative;
+ display:inline-flex;
+ vertical-align:middle
+}
+.btn-group-vertical>.btn,
+.btn-group>.btn {
+ position:relative;
+ flex:1 1 auto
+}
+.btn-group-vertical>.btn:hover,
+.btn-group>.btn:hover {
+ z-index:1
+}
+.btn-group-vertical>.btn.active,
+.btn-group-vertical>.btn:active,
+.btn-group-vertical>.btn:focus,
+.btn-group>.btn.active,
+.btn-group>.btn:active,
+.btn-group>.btn:focus {
+ z-index:1
+}
+.btn-toolbar {
+ display:flex;
+ flex-wrap:wrap;
+ justify-content:flex-start
+}
+.btn-toolbar .input-group {
+ width:auto
+}
+.btn-group>.btn-group:not(:first-child),
+.btn-group>.btn:not(:first-child) {
+ margin-left:-1px
+}
+.btn-group>.btn-group:not(:last-child)>.btn,
+.btn-group>.btn:not(:last-child):not(.dropdown-toggle) {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.btn-group>.btn-group:not(:first-child)>.btn,
+.btn-group>.btn:not(:first-child) {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.dropdown-toggle-split {
+ padding-right:.5625rem;
+ padding-left:.5625rem
+}
+.dropdown-toggle-split::after,
+.dropright .dropdown-toggle-split::after,
+.dropup .dropdown-toggle-split::after {
+ margin-left:0
+}
+.dropleft .dropdown-toggle-split::before {
+ margin-right:0
+}
+.btn-group-sm>.btn+.dropdown-toggle-split,
+.btn-sm+.dropdown-toggle-split {
+ padding-right:.375rem;
+ padding-left:.375rem
+}
+.btn-group-lg>.btn+.dropdown-toggle-split,
+.btn-lg+.dropdown-toggle-split {
+ padding-right:.75rem;
+ padding-left:.75rem
+}
+.btn-group-vertical {
+ flex-direction:column;
+ align-items:flex-start;
+ justify-content:center
+}
+.btn-group-vertical>.btn,
+.btn-group-vertical>.btn-group {
+ width:100%
+}
+.btn-group-vertical>.btn-group:not(:first-child),
+.btn-group-vertical>.btn:not(:first-child) {
+ margin-top:-1px
+}
+.btn-group-vertical>.btn-group:not(:last-child)>.btn,
+.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle) {
+ border-bottom-right-radius:0;
+ border-bottom-left-radius:0
+}
+.btn-group-vertical>.btn-group:not(:first-child)>.btn,
+.btn-group-vertical>.btn:not(:first-child) {
+ border-top-left-radius:0;
+ border-top-right-radius:0
+}
+.btn-group-toggle>.btn,
+.btn-group-toggle>.btn-group>.btn {
+ margin-bottom:0
+}
+.btn-group-toggle>.btn input[type=checkbox],
+.btn-group-toggle>.btn input[type=radio],
+.btn-group-toggle>.btn-group>.btn input[type=checkbox],
+.btn-group-toggle>.btn-group>.btn input[type=radio] {
+ position:absolute;
+ clip:rect(0,0,0,0);
+ pointer-events:none
+}
+.input-group {
+ position:relative;
+ display:flex;
+ flex-wrap:wrap;
+ align-items:stretch;
+ width:100%
+}
+.input-group>.custom-file,
+.input-group>.custom-select,
+.input-group>.form-control,
+.input-group>.form-control-plaintext {
+ position:relative;
+ flex:1 1 auto;
+ width:1%;
+ min-width:0;
+ margin-bottom:0
+}
+.input-group>.custom-file+.custom-file,
+.input-group>.custom-file+.custom-select,
+.input-group>.custom-file+.form-control,
+.input-group>.custom-select+.custom-file,
+.input-group>.custom-select+.custom-select,
+.input-group>.custom-select+.form-control,
+.input-group>.form-control+.custom-file,
+.input-group>.form-control+.custom-select,
+.input-group>.form-control+.form-control,
+.input-group>.form-control-plaintext+.custom-file,
+.input-group>.form-control-plaintext+.custom-select,
+.input-group>.form-control-plaintext+.form-control {
+ margin-left:-1px
+}
+.input-group>.custom-file .custom-file-input:focus~.custom-file-label,
+.input-group>.custom-select:focus,
+.input-group>.form-control:focus {
+ z-index:3
+}
+.input-group>.custom-file .custom-file-input:focus {
+ z-index:4
+}
+.input-group>.custom-select:not(:last-child),
+.input-group>.form-control:not(:last-child) {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.input-group>.custom-select:not(:first-child),
+.input-group>.form-control:not(:first-child) {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.input-group>.custom-file {
+ display:flex;
+ align-items:center
+}
+.input-group>.custom-file:not(:last-child) .custom-file-label,
+.input-group>.custom-file:not(:last-child) .custom-file-label::after {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.input-group>.custom-file:not(:first-child) .custom-file-label {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.input-group-append,
+.input-group-prepend {
+ display:flex
+}
+.input-group-append .btn,
+.input-group-prepend .btn {
+ position:relative;
+ z-index:2
+}
+.input-group-append .btn:focus,
+.input-group-prepend .btn:focus {
+ z-index:3
+}
+.input-group-append .btn+.btn,
+.input-group-append .btn+.input-group-text,
+.input-group-append .input-group-text+.btn,
+.input-group-append .input-group-text+.input-group-text,
+.input-group-prepend .btn+.btn,
+.input-group-prepend .btn+.input-group-text,
+.input-group-prepend .input-group-text+.btn,
+.input-group-prepend .input-group-text+.input-group-text {
+ margin-left:-1px
+}
+.input-group-prepend {
+ margin-right:-1px
+}
+.input-group-append {
+ margin-left:-1px
+}
+.input-group-text {
+ display:flex;
+ align-items:center;
+ padding:.375rem .75rem;
+ margin-bottom:0;
+ font-size:1rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#495057;
+ text-align:center;
+ white-space:nowrap;
+ background-color:#e9ecef;
+ border:1px solid #ced4da;
+ border-radius:.5rem
+}
+.input-group-text input[type=checkbox],
+.input-group-text input[type=radio] {
+ margin-top:0
+}
+.input-group-lg>.custom-select,
+.input-group-lg>.form-control:not(textarea) {
+ height:calc(1.5em + 1rem + 2px)
+}
+.input-group-lg>.custom-select,
+.input-group-lg>.form-control,
+.input-group-lg>.input-group-append>.btn,
+.input-group-lg>.input-group-append>.input-group-text,
+.input-group-lg>.input-group-prepend>.btn,
+.input-group-lg>.input-group-prepend>.input-group-text {
+ padding:.5rem 1rem;
+ font-size:1.25rem;
+ line-height:1.5;
+ border-radius:.5rem
+}
+.input-group-sm>.custom-select,
+.input-group-sm>.form-control:not(textarea) {
+ height:calc(1.5em + .5rem + 2px)
+}
+.input-group-sm>.custom-select,
+.input-group-sm>.form-control,
+.input-group-sm>.input-group-append>.btn,
+.input-group-sm>.input-group-append>.input-group-text,
+.input-group-sm>.input-group-prepend>.btn,
+.input-group-sm>.input-group-prepend>.input-group-text {
+ padding:.25rem .5rem;
+ font-size:.875rem;
+ line-height:1.5;
+ border-radius:1rem
+}
+.input-group-lg>.custom-select,
+.input-group-sm>.custom-select {
+ padding-right:1.75rem
+}
+.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),
+.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),
+.input-group>.input-group-append:not(:last-child)>.btn,
+.input-group>.input-group-append:not(:last-child)>.input-group-text,
+.input-group>.input-group-prepend>.btn,
+.input-group>.input-group-prepend>.input-group-text {
+ border-top-right-radius:0;
+ border-bottom-right-radius:0
+}
+.input-group>.input-group-append>.btn,
+.input-group>.input-group-append>.input-group-text,
+.input-group>.input-group-prepend:first-child>.btn:not(:first-child),
+.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),
+.input-group>.input-group-prepend:not(:first-child)>.btn,
+.input-group>.input-group-prepend:not(:first-child)>.input-group-text {
+ border-top-left-radius:0;
+ border-bottom-left-radius:0
+}
+.custom-control {
+ position:relative;
+ display:block;
+ min-height:1.5rem;
+ padding-left:1.5rem
+}
+.custom-control-inline {
+ display:inline-flex;
+ margin-right:1rem
+}
+.custom-control-input {
+ position:absolute;
+ left:0;
+ z-index:-1;
+ width:1rem;
+ height:1.25rem;
+ opacity:0
+}
+.custom-control-input:checked~.custom-control-label::before {
+ color:#fff;
+ border-color:#f1641e;
+ background-color:#f1641e
+}
+.custom-control-input:focus~.custom-control-label::before {
+ box-shadow:0 0 0 .2rem rgba(241,30,30,.75)
+}
+.custom-control-input:focus:not(:checked)~.custom-control-label::before {
+ border-color:#f89696
+}
+.custom-control-input:not(:disabled):active~.custom-control-label::before {
+ color:#fff;
+ background-color:#fbd8c6;
+ border-color:#fbd8c6
+}
+.custom-control-input:disabled~.custom-control-label,
+.custom-control-input[disabled]~.custom-control-label {
+ color:#6c757d
+}
+.custom-control-input:disabled~.custom-control-label::before,
+.custom-control-input[disabled]~.custom-control-label::before {
+ background-color:#e9ecef
+}
+.custom-control-label {
+ position:relative;
+ margin-bottom:0;
+ vertical-align:top
+}
+.custom-control-label::before {
+ position:absolute;
+ top:.25rem;
+ left:-1.5rem;
+ display:block;
+ width:1rem;
+ height:1rem;
+ pointer-events:none;
+ content:"";
+ background-color:#fff;
+ border:#adb5bd solid 1px
+}
+.custom-control-label::after {
+ position:absolute;
+ top:.25rem;
+ left:-1.5rem;
+ display:block;
+ width:1rem;
+ height:1rem;
+ content:"";
+ background:no-repeat 50%/50% 50%
+}
+.custom-checkbox .custom-control-label::before {
+ border-radius:.5rem
+}
+.custom-checkbox .custom-control-input:checked~.custom-control-label::after {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23ffffff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")
+}
+.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before {
+ border-color:#f1641e;
+ background-color:#f1641e
+}
+.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%23ffffff' d='M0 2h4'/%3e%3c/svg%3e")
+}
+.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before {
+ background-color:rgba(241,100,30,.5)
+}
+.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before {
+ background-color:rgba(241,100,30,.5)
+}
+.custom-radio .custom-control-label::before {
+ border-radius:50%
+}
+.custom-radio .custom-control-input:checked~.custom-control-label::after {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")
+}
+.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before {
+ background-color:rgba(241,100,30,.5)
+}
+.custom-switch {
+ padding-left:2.25rem
+}
+.custom-switch .custom-control-label::before {
+ left:-2.25rem;
+ width:1.75rem;
+ pointer-events:all;
+ border-radius:.5rem
+}
+.custom-switch .custom-control-label::after {
+ top:calc(.25rem + 2px);
+ left:calc(-2.25rem + 2px);
+ width:calc(1rem - 4px);
+ height:calc(1rem - 4px);
+ background-color:#adb5bd;
+ border-radius:.5rem;
+ transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-switch .custom-control-label::after {
+  transition:none
+ }
+}
+.custom-switch .custom-control-input:checked~.custom-control-label::after {
+ background-color:#fff;
+ transform:translateX(.75rem)
+}
+.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before {
+ background-color:rgba(241,100,30,.5)
+}
+.custom-select {
+ display:inline-block;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ padding:.375rem 1.75rem .375rem .75rem;
+ font-size:1rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#495057;
+ vertical-align:middle;
+ background:#fff url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;
+ border:1px solid #ced4da;
+ border-radius:.5rem;
+ appearance:none
+}
+.custom-select:focus {
+ border-color:#f89696;
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(241, 30, 30, 0.75);
+}
+.custom-select:focus::-ms-value {
+ color:#495057;
+ background-color:#fff
+}
+.custom-select[multiple],
+.custom-select[size]:not([size="1"]) {
+ height:auto;
+ padding-right:.75rem;
+ background-image:none
+}
+.custom-select:disabled {
+ color:#6c757d;
+ background-color:#e9ecef
+}
+.custom-select::-ms-expand {
+ display:none
+}
+.custom-select:-moz-focusring {
+ color:transparent;
+ text-shadow:0 0 0 #495057
+}
+.custom-select-sm {
+ height:calc(1.5em + .5rem + 2px);
+ padding-top:.25rem;
+ padding-bottom:.25rem;
+ padding-left:.5rem;
+ font-size:.875rem
+}
+.custom-select-lg {
+ height:calc(1.5em + 1rem + 2px);
+ padding-top:.5rem;
+ padding-bottom:.5rem;
+ padding-left:1rem;
+ font-size:1.25rem
+}
+.custom-file {
+ position:relative;
+ display:inline-block;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ margin-bottom:0
+}
+.custom-file-input {
+ position:relative;
+ z-index:2;
+ width:100%;
+ height:calc(1.5em + .75rem + 2px);
+ margin:0;
+ opacity:0
+}
+.custom-file-input:focus~.custom-file-label {
+ border-color:#f89696;
+ box-shadow:0 0 0 .2rem rgba(241,30,30,.75)
+}
+.custom-file-input:disabled~.custom-file-label,
+.custom-file-input[disabled]~.custom-file-label {
+ background-color:#e9ecef
+}
+.custom-file-input:lang(en)~.custom-file-label::after {
+ content:"Browse"
+}
+.custom-file-input~.custom-file-label[data-browse]::after {
+ content:attr(data-browse)
+}
+.custom-file-label {
+ position:absolute;
+ top:0;
+ right:0;
+ left:0;
+ z-index:1;
+ height:calc(1.5em + .75rem + 2px);
+ padding:.375rem .75rem;
+ font-weight:400;
+ line-height:1.5;
+ color:#495057;
+ background-color:#fff;
+ border:1px solid #ced4da;
+ border-radius:.5rem
+}
+.custom-file-label::after {
+ position:absolute;
+ top:0;
+ right:0;
+ bottom:0;
+ z-index:3;
+ display:block;
+ height:calc(1.5em + .75rem);
+ padding:.375rem .75rem;
+ line-height:1.5;
+ color:#495057;
+ content:"Browse";
+ background-color:#e9ecef;
+ border-left:inherit;
+ border-radius:0 .5rem .5rem 0
+}
+.custom-range {
+ width:100%;
+ height:1.4rem;
+ padding:0;
+ background-color:transparent;
+ appearance:none
+}
+.custom-range:focus {
+ outline:0
+}
+.custom-range:focus::-webkit-slider-thumb {
+ box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(241,30,30,.75)
+}
+.custom-range:focus::-moz-range-thumb {
+ box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(241,30,30,.75)
+}
+.custom-range:focus::-ms-thumb {
+ box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(241,30,30,.75)
+}
+.custom-range::-moz-focus-outer {
+ border:0
+}
+.custom-range::-webkit-slider-thumb {
+ width:1rem;
+ height:1rem;
+ margin-top:-.25rem;
+ background-color:#f1641e;
+ border:0;
+ border-radius:1rem;
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
+ appearance:none
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-range::-webkit-slider-thumb {
+  transition:none
+ }
+}
+.custom-range::-webkit-slider-thumb:active {
+ background-color:#fbd8c6
+}
+.custom-range::-webkit-slider-runnable-track {
+ width:100%;
+ height:.5rem;
+ color:transparent;
+ cursor:pointer;
+ background-color:#dee2e6;
+ border-color:transparent;
+ border-radius:1rem
+}
+.custom-range::-moz-range-thumb {
+ width:1rem;
+ height:1rem;
+ background-color:#f1641e;
+ border:0;
+ border-radius:1rem;
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
+ appearance:none
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-range::-moz-range-thumb {
+  transition:none
+ }
+}
+.custom-range::-moz-range-thumb:active {
+ background-color:#fbd8c6
+}
+.custom-range::-moz-range-track {
+ width:100%;
+ height:.5rem;
+ color:transparent;
+ cursor:pointer;
+ background-color:#dee2e6;
+ border-color:transparent;
+ border-radius:1rem
+}
+.custom-range::-ms-thumb {
+ width:1rem;
+ height:1rem;
+ margin-top:0;
+ margin-right:.2rem;
+ margin-left:.2rem;
+ background-color:#f1641e;
+ border:0;
+ border-radius:1rem;
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
+ appearance:none
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-range::-ms-thumb {
+  transition:none
+ }
+}
+.custom-range::-ms-thumb:active {
+ background-color:#fbd8c6
+}
+.custom-range::-ms-track {
+ width:100%;
+ height:.5rem;
+ color:transparent;
+ cursor:pointer;
+ background-color:transparent;
+ border-color:transparent;
+ border-width:.5rem
+}
+.custom-range::-ms-fill-lower {
+ background-color:#dee2e6;
+ border-radius:1rem
+}
+.custom-range::-ms-fill-upper {
+ margin-right:15px;
+ background-color:#dee2e6;
+ border-radius:1rem
+}
+.custom-range:disabled::-webkit-slider-thumb {
+ background-color:#adb5bd
+}
+.custom-range:disabled::-webkit-slider-runnable-track {
+ cursor:default
+}
+.custom-range:disabled::-moz-range-thumb {
+ background-color:#adb5bd
+}
+.custom-range:disabled::-moz-range-track {
+ cursor:default
+}
+.custom-range:disabled::-ms-thumb {
+ background-color:#adb5bd
+}
+.custom-control-label::before,
+.custom-file-label,
+.custom-select {
+ transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .custom-control-label::before,
+ .custom-file-label,
+ .custom-select {
+  transition:none
+ }
+}
+.nav {
+ display:flex;
+ flex-wrap:wrap;
+ padding-left:0;
+ margin-bottom:0;
+ list-style:none
+}
+.nav-link {
+ display:block;
+ padding:.5rem 1rem
+}
+.nav-link:focus,
+.nav-link:hover {
+ text-decoration:none
+}
+.nav-link.disabled {
+ color:#6c757d;
+ pointer-events:none;
+ cursor:default
+}
+.nav-tabs {
+ border-bottom:1px solid #dee2e6
+}
+.nav-tabs .nav-item {
+ margin-bottom:-1px
+}
+.nav-tabs .nav-link {
+ border:1px solid transparent;
+ border-top-left-radius:.5rem;
+ border-top-right-radius:.5rem
+}
+.nav-tabs .nav-link:focus,
+.nav-tabs .nav-link:hover {
+ border-color:#e9ecef #e9ecef #dee2e6
+}
+.nav-tabs .nav-link.disabled {
+ color:#6c757d;
+ background-color:transparent;
+ border-color:transparent
+}
+.nav-tabs .nav-item.show .nav-link,
+.nav-tabs .nav-link.active {
+ color:#495057;
+ background-color:#fff;
+ border-color:#dee2e6 #dee2e6 #fff
+}
+.nav-tabs .dropdown-menu {
+ margin-top:-1px;
+ border-top-left-radius:0;
+ border-top-right-radius:0
+}
+.nav-pills .nav-link {
+ border-radius:.5rem
+}
+.nav-pills .nav-link.active,
+.nav-pills .show>.nav-link {
+ color:#fff;
+ background-color:#f1641e
+}
+.nav-fill .nav-item {
+ flex:1 1 auto;
+ text-align:center
+}
+.nav-justified .nav-item {
+ flex-basis:0;
+ flex-grow:1;
+ text-align:center
+}
+.tab-content>.tab-pane {
+ display:none
+}
+.tab-content>.active {
+ display:block
+}
+.navbar {
+ position:relative;
+ display:flex;
+ flex-wrap:wrap;
+ align-items:center;
+ justify-content:space-between;
+ padding:.5rem 1rem
+}
+.navbar .container,
+.navbar .container-fluid,
+.navbar .container-lg,
+.navbar .container-md,
+.navbar .container-sm,
+.navbar .container-xl {
+ display:flex;
+ flex-wrap:wrap;
+ align-items:center;
+ justify-content:space-between
+}
+.navbar-brand {
+ display:inline-block;
+ padding-top:.3125rem;
+ padding-bottom:.3125rem;
+ margin-right:1rem;
+ font-size:1.25rem;
+ line-height:inherit;
+ white-space:nowrap
+}
+.navbar-brand:focus,
+.navbar-brand:hover {
+ text-decoration:none
+}
+.navbar-nav {
+ display:flex;
+ flex-direction:column;
+ padding-left:0;
+ margin-bottom:0;
+ list-style:none
+}
+.navbar-nav .nav-link {
+ padding-right:0;
+ padding-left:0
+}
+.navbar-nav .dropdown-menu {
+ position:static;
+ float:none
+}
+.navbar-text {
+ display:inline-block;
+ padding-top:.5rem;
+ padding-bottom:.5rem
+}
+.navbar-collapse {
+ flex-basis:100%;
+ flex-grow:1;
+ align-items:center
+}
+.navbar-toggler {
+ padding:.25rem .75rem;
+ font-size:1.25rem;
+ line-height:1;
+ background-color:transparent;
+ border:1px solid transparent;
+ border-radius:.5rem
+}
+.navbar-toggler:focus,
+.navbar-toggler:hover {
+ text-decoration:none
+}
+.navbar-toggler-icon {
+ display:inline-block;
+ width:1.5em;
+ height:1.5em;
+ vertical-align:middle;
+ content:"";
+ background:no-repeat center center;
+ background-size:100% 100%
+}
+@media (max-width:575.98px) {
+ .navbar-expand-sm>.container,
+ .navbar-expand-sm>.container-fluid,
+ .navbar-expand-sm>.container-lg,
+ .navbar-expand-sm>.container-md,
+ .navbar-expand-sm>.container-sm,
+ .navbar-expand-sm>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:576px) {
+ .navbar-expand-sm {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-sm .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-sm .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-sm .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-sm>.container,
+ .navbar-expand-sm>.container-fluid,
+ .navbar-expand-sm>.container-lg,
+ .navbar-expand-sm>.container-md,
+ .navbar-expand-sm>.container-sm,
+ .navbar-expand-sm>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-sm .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-sm .navbar-toggler {
+  display:none
+ }
+}
+@media (max-width:767.98px) {
+ .navbar-expand-md>.container,
+ .navbar-expand-md>.container-fluid,
+ .navbar-expand-md>.container-lg,
+ .navbar-expand-md>.container-md,
+ .navbar-expand-md>.container-sm,
+ .navbar-expand-md>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:768px) {
+ .navbar-expand-md {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-md .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-md .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-md .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-md>.container,
+ .navbar-expand-md>.container-fluid,
+ .navbar-expand-md>.container-lg,
+ .navbar-expand-md>.container-md,
+ .navbar-expand-md>.container-sm,
+ .navbar-expand-md>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-md .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-md .navbar-toggler {
+  display:none
+ }
+}
+@media (max-width:991.98px) {
+ .navbar-expand-lg>.container,
+ .navbar-expand-lg>.container-fluid,
+ .navbar-expand-lg>.container-lg,
+ .navbar-expand-lg>.container-md,
+ .navbar-expand-lg>.container-sm,
+ .navbar-expand-lg>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:992px) {
+ .navbar-expand-lg {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-lg .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-lg .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-lg .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-lg>.container,
+ .navbar-expand-lg>.container-fluid,
+ .navbar-expand-lg>.container-lg,
+ .navbar-expand-lg>.container-md,
+ .navbar-expand-lg>.container-sm,
+ .navbar-expand-lg>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-lg .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-lg .navbar-toggler {
+  display:none
+ }
+}
+@media (max-width:1199.98px) {
+ .navbar-expand-xl>.container,
+ .navbar-expand-xl>.container-fluid,
+ .navbar-expand-xl>.container-lg,
+ .navbar-expand-xl>.container-md,
+ .navbar-expand-xl>.container-sm,
+ .navbar-expand-xl>.container-xl {
+  padding-right:0;
+  padding-left:0
+ }
+}
+@media (min-width:1200px) {
+ .navbar-expand-xl {
+  flex-flow:row nowrap;
+  justify-content:flex-start
+ }
+ .navbar-expand-xl .navbar-nav {
+  flex-direction:row
+ }
+ .navbar-expand-xl .navbar-nav .dropdown-menu {
+  position:absolute
+ }
+ .navbar-expand-xl .navbar-nav .nav-link {
+  padding-right:.5rem;
+  padding-left:.5rem
+ }
+ .navbar-expand-xl>.container,
+ .navbar-expand-xl>.container-fluid,
+ .navbar-expand-xl>.container-lg,
+ .navbar-expand-xl>.container-md,
+ .navbar-expand-xl>.container-sm,
+ .navbar-expand-xl>.container-xl {
+  flex-wrap:nowrap
+ }
+ .navbar-expand-xl .navbar-collapse {
+  display:flex!important;
+  flex-basis:auto
+ }
+ .navbar-expand-xl .navbar-toggler {
+  display:none
+ }
+}
+.navbar-expand {
+ flex-flow:row nowrap;
+ justify-content:flex-start
+}
+.navbar-expand>.container,
+.navbar-expand>.container-fluid,
+.navbar-expand>.container-lg,
+.navbar-expand>.container-md,
+.navbar-expand>.container-sm,
+.navbar-expand>.container-xl {
+ padding-right:0;
+ padding-left:0
+}
+.navbar-expand .navbar-nav {
+ flex-direction:row
+}
+.navbar-expand .navbar-nav .dropdown-menu {
+ position:absolute
+}
+.navbar-expand .navbar-nav .nav-link {
+ padding-right:.5rem;
+ padding-left:.5rem
+}
+.navbar-expand>.container,
+.navbar-expand>.container-fluid,
+.navbar-expand>.container-lg,
+.navbar-expand>.container-md,
+.navbar-expand>.container-sm,
+.navbar-expand>.container-xl {
+ flex-wrap:nowrap
+}
+.navbar-expand .navbar-collapse {
+ display:flex!important;
+ flex-basis:auto
+}
+.navbar-expand .navbar-toggler {
+ display:none
+}
+.navbar-light .navbar-brand {
+ color:#212529
+}
+.navbar-light .navbar-brand:focus,
+.navbar-light .navbar-brand:hover {
+ color:#212529
+}
+.navbar-light .navbar-nav .nav-link {
+ color:#6c757d
+}
+.navbar-light .navbar-nav .nav-link:focus,
+.navbar-light .navbar-nav .nav-link:hover {
+ color:#212529
+}
+.navbar-light .navbar-nav .nav-link.disabled {
+ color:rgba(34,34,34,.3)
+}
+.navbar-light .navbar-nav .active>.nav-link,
+.navbar-light .navbar-nav .nav-link.active,
+.navbar-light .navbar-nav .nav-link.show,
+.navbar-light .navbar-nav .show>.nav-link {
+ color:#212529
+}
+.navbar-light .navbar-toggler {
+ color:#6c757d;
+ border-color:rgba(34,34,34,.1)
+}
+.navbar-light .navbar-toggler-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='%236c757d' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")
+}
+.navbar-light .navbar-text {
+ color:#6c757d
+}
+.navbar-light .navbar-text a {
+ color:#212529
+}
+.navbar-light .navbar-text a:focus,
+.navbar-light .navbar-text a:hover {
+ color:#212529
+}
+.navbar-dark .navbar-brand {
+ color:#fff
+}
+.navbar-dark .navbar-brand:focus,
+.navbar-dark .navbar-brand:hover {
+ color:#fff
+}
+.navbar-dark .navbar-nav .nav-link {
+ color:rgba(255,255,255,.5)
+}
+.navbar-dark .navbar-nav .nav-link:focus,
+.navbar-dark .navbar-nav .nav-link:hover {
+ color:rgba(255,255,255,.75)
+}
+.navbar-dark .navbar-nav .nav-link.disabled {
+ color:rgba(255,255,255,.25)
+}
+.navbar-dark .navbar-nav .active>.nav-link,
+.navbar-dark .navbar-nav .nav-link.active,
+.navbar-dark .navbar-nav .nav-link.show,
+.navbar-dark .navbar-nav .show>.nav-link {
+ color:#fff
+}
+.navbar-dark .navbar-toggler {
+ color:rgba(255,255,255,.5);
+ border-color:rgba(34,34,34,.1)
+}
+.navbar-dark .navbar-toggler-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.5%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")
+}
+.navbar-dark .navbar-text {
+ color:rgba(255,255,255,.5)
+}
+.navbar-dark .navbar-text a {
+ color:#fff
+}
+.navbar-dark .navbar-text a:focus,
+.navbar-dark .navbar-text a:hover {
+ color:#fff
+}
+.card {
+ position:relative;
+ display:flex;
+ flex-direction:column;
+ min-width:0;
+ word-wrap:break-word;
+ background-color:#f8f9fa;
+ background-clip:border-box;
+ border:1px solid rgba(34,34,34,.125);
+ border-radius:.5rem
+}
+.card>hr {
+ margin-right:0;
+ margin-left:0
+}
+.card>.list-group {
+ border-top:inherit;
+ border-bottom:inherit
+}
+.card>.list-group:first-child {
+ border-top-width:0;
+ border-top-left-radius:calc(.5rem - 1px);
+ border-top-right-radius:calc(.5rem - 1px)
+}
+.card>.list-group:last-child {
+ border-bottom-width:0;
+ border-bottom-right-radius:calc(.5rem - 1px);
+ border-bottom-left-radius:calc(.5rem - 1px)
+}
+.card-body {
+ flex:1 1 auto;
+ min-height:1px;
+ padding:1.25rem;
+ color:#495057
+}
+.card-title {
+ margin-bottom:.75rem
+}
+.card-subtitle {
+ margin-top:-.375rem;
+ margin-bottom:0
+}
+.card-text:last-child {
+ margin-bottom:0
+}
+.card-link:hover {
+ text-decoration:none
+}
+.card-link+.card-link {
+ margin-left:1.25rem
+}
+.card-header {
+ padding:.75rem 1.25rem;
+ margin-bottom:0;
+ color:#495057;
+ background-color:rgba(34,34,34,.03);
+ border-bottom:1px solid rgba(34,34,34,.125)
+}
+.card-header:first-child {
+ border-radius:calc(.5rem - 1px) calc(.5rem - 1px) 0 0
+}
+.card-header+.list-group .list-group-item:first-child {
+ border-top:0
+}
+.card-footer {
+ padding:.75rem 1.25rem;
+ color:#495057;
+ background-color:rgba(34,34,34,.03);
+ border-top:1px solid rgba(34,34,34,.125)
+}
+.card-footer:last-child {
+ border-radius:0 0 calc(.5rem - 1px) calc(.5rem - 1px)
+}
+.card-header-tabs {
+ margin-right:-.625rem;
+ margin-bottom:-.75rem;
+ margin-left:-.625rem;
+ border-bottom:0
+}
+.card-header-pills {
+ margin-right:-.625rem;
+ margin-left:-.625rem
+}
+.card-img-overlay {
+ position:absolute;
+ top:0;
+ right:0;
+ bottom:0;
+ left:0;
+ padding:1.25rem
+}
+.card-img,
+.card-img-bottom,
+.card-img-top {
+ flex-shrink:0;
+ width:100%
+}
+.card-img,
+.card-img-top {
+ border-top-left-radius:calc(.5rem - 1px);
+ border-top-right-radius:calc(.5rem - 1px)
+}
+.card-img,
+.card-img-bottom {
+ border-bottom-right-radius:calc(.5rem - 1px);
+ border-bottom-left-radius:calc(.5rem - 1px)
+}
+.card-deck .card {
+ margin-bottom:15px
+}
+@media (min-width:576px) {
+ .card-deck {
+  display:flex;
+  flex-flow:row wrap;
+  margin-right:-15px;
+  margin-left:-15px
+ }
+ .card-deck .card {
+  flex:1 0 0%;
+  margin-right:15px;
+  margin-bottom:0;
+  margin-left:15px
+ }
+}
+.card-group>.card {
+ margin-bottom:15px
+}
+@media (min-width:576px) {
+ .card-group {
+  display:flex;
+  flex-flow:row wrap
+ }
+ .card-group>.card {
+  flex:1 0 0%;
+  margin-bottom:0
+ }
+ .card-group>.card+.card {
+  margin-left:0;
+  border-left:0
+ }
+ .card-group>.card:not(:last-child) {
+  border-top-right-radius:0;
+  border-bottom-right-radius:0
+ }
+ .card-group>.card:not(:last-child) .card-header,
+ .card-group>.card:not(:last-child) .card-img-top {
+  border-top-right-radius:0
+ }
+ .card-group>.card:not(:last-child) .card-footer,
+ .card-group>.card:not(:last-child) .card-img-bottom {
+  border-bottom-right-radius:0
+ }
+ .card-group>.card:not(:first-child) {
+  border-top-left-radius:0;
+  border-bottom-left-radius:0
+ }
+ .card-group>.card:not(:first-child) .card-header,
+ .card-group>.card:not(:first-child) .card-img-top {
+  border-top-left-radius:0
+ }
+ .card-group>.card:not(:first-child) .card-footer,
+ .card-group>.card:not(:first-child) .card-img-bottom {
+  border-bottom-left-radius:0
+ }
+}
+.card-columns .card {
+ margin-bottom:.75rem
+}
+@media (min-width:576px) {
+ .card-columns {
+  column-count:3;
+  column-gap:1.25rem;
+  orphans:1;
+  widows:1
+ }
+ .card-columns .card {
+  display:inline-block;
+  width:100%
+ }
+}
+.accordion>.card {
+ overflow:hidden
+}
+.accordion>.card:not(:last-of-type) {
+ border-bottom:0;
+ border-bottom-right-radius:0;
+ border-bottom-left-radius:0
+}
+.accordion>.card:not(:first-of-type) {
+ border-top-left-radius:0;
+ border-top-right-radius:0
+}
+.accordion>.card>.card-header {
+ border-radius:0;
+ margin-bottom:-1px
+}
+.breadcrumb {
+ display:flex;
+ flex-wrap:wrap;
+ padding:.75rem 1rem;
+ margin-bottom:1rem;
+ list-style:none;
+ background-color:#e9ecef;
+ border-radius:.5rem
+}
+.breadcrumb-item {
+ display:flex
+}
+.breadcrumb-item+.breadcrumb-item {
+ padding-left:.5rem
+}
+.breadcrumb-item+.breadcrumb-item::before {
+ display:inline-block;
+ padding-right:.5rem;
+ color:#6c757d;
+ content:"/"
+}
+.breadcrumb-item+.breadcrumb-item:hover::before {
+ text-decoration:underline
+}
+.breadcrumb-item+.breadcrumb-item:hover::before {
+ text-decoration:none
+}
+.breadcrumb-item.active {
+ color:#6c757d
+}
+.pagination {
+ display:flex;
+ padding-left:0;
+ list-style:none;
+ border-radius:.5rem
+}
+.page-link {
+ position:relative;
+ display:block;
+ padding:.5rem .75rem;
+ margin-left:-1px;
+ line-height:1.25;
+ color:#f1641e;
+ background-color:#fff;
+ border:1px solid #dee2e6
+}
+.page-link:hover {
+ z-index:2;
+ color:#b7440b;
+ text-decoration:none;
+ background-color:#e9ecef;
+ border-color:#dee2e6
+}
+.page-link:focus {
+ z-index:3;
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(241,30,30,.75)
+}
+.page-item:first-child .page-link {
+ margin-left:0;
+ border-top-left-radius:.5rem;
+ border-bottom-left-radius:.5rem
+}
+.page-item:last-child .page-link {
+ border-top-right-radius:.5rem;
+ border-bottom-right-radius:.5rem
+}
+.page-item.active .page-link {
+ z-index:3;
+ color:#fff;
+ background-color:#f1641e;
+ border-color:#f1641e
+}
+.page-item.disabled .page-link {
+ color:#6c757d;
+ pointer-events:none;
+ cursor:auto;
+ background-color:#fff;
+ border-color:#dee2e6
+}
+.pagination-lg .page-link {
+ padding:.75rem 1.5rem;
+ font-size:1.25rem;
+ line-height:1.5
+}
+.pagination-lg .page-item:first-child .page-link {
+ border-top-left-radius:.5rem;
+ border-bottom-left-radius:.5rem
+}
+.pagination-lg .page-item:last-child .page-link {
+ border-top-right-radius:.5rem;
+ border-bottom-right-radius:.5rem
+}
+.pagination-sm .page-link {
+ padding:.25rem .5rem;
+ font-size:.875rem;
+ line-height:1.5
+}
+.pagination-sm .page-item:first-child .page-link {
+ border-top-left-radius:1rem;
+ border-bottom-left-radius:1rem
+}
+.pagination-sm .page-item:last-child .page-link {
+ border-top-right-radius:1rem;
+ border-bottom-right-radius:1rem
+}
+.badge {
+ display:inline-block;
+ padding:.25em .4em;
+ font-size:75%;
+ font-weight:600;
+ line-height:1;
+ text-align:center;
+ white-space:nowrap;
+ vertical-align:baseline;
+ border-radius:.5rem;
+ transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .badge {
+  transition:none
+ }
+}
+a.badge:focus,
+a.badge:hover {
+ text-decoration:none
+}
+.badge:empty {
+ display:none
+}
+.btn .badge {
+ position:relative;
+ top:-1px
+}
+.badge-pill {
+ padding-right:.6em;
+ padding-left:.6em;
+ border-radius:10rem
+}
+.badge-primary {
+ color:#fff;
+ background-color:#f1641e
+}
+a.badge-primary:focus,
+a.badge-primary:hover {
+ color:#fff;
+ background-color:#cf4d0d
+}
+a.badge-primary.focus,
+a.badge-primary:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(241,100,30,.5)
+}
+.badge-secondary {
+ color:#fff;
+ background-color:#c80000;
+}
+a.badge-secondary:focus,
+a.badge-secondary:hover {
+ color:#fff;
+ background-color:#00953e
+}
+a.badge-secondary.focus,
+a.badge-secondary:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(0,200,83,.5)
+}
+.badge-success {
+ color:#fff;
+ background-color:#6610f2
+}
+a.badge-success:focus,
+a.badge-success:hover {
+ color:#fff;
+ background-color:#510bc4
+}
+a.badge-success.focus,
+a.badge-success:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(102,16,242,.5)
+}
+.badge-info {
+ color:#fff;
+ background-color:#007bff
+}
+a.badge-info:focus,
+a.badge-info:hover {
+ color:#fff;
+ background-color:#0062cc
+}
+a.badge-info.focus,
+a.badge-info:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(0,123,255,.5)
+}
+.badge-warning {
+ color:#212529;
+ background-color:#ffc107
+}
+a.badge-warning:focus,
+a.badge-warning:hover {
+ color:#212529;
+ background-color:#d39e00
+}
+a.badge-warning.focus,
+a.badge-warning:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(255,193,7,.5)
+}
+.badge-danger {
+ color:#fff;
+ background-color:#873208
+}
+a.badge-danger:focus,
+a.badge-danger:hover {
+ color:#fff;
+ background-color:#572105
+}
+a.badge-danger.focus,
+a.badge-danger:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(135,50,8,.5)
+}
+.badge-light {
+ color:#212529;
+ background-color:#f8f9fa
+}
+a.badge-light:focus,
+a.badge-light:hover {
+ color:#212529;
+ background-color:#dae0e5
+}
+a.badge-light.focus,
+a.badge-light:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(248,249,250,.5)
+}
+.badge-dark {
+ color:#fff;
+ background-color:#343a40
+}
+a.badge-dark:focus,
+a.badge-dark:hover {
+ color:#fff;
+ background-color:#1d2124
+}
+a.badge-dark.focus,
+a.badge-dark:focus {
+ outline:0;
+ box-shadow:0 0 0 .2rem rgba(52,58,64,.5)
+}
+.jumbotron {
+ padding:2rem 1rem;
+ margin-bottom:2rem;
+ background-color:#e9ecef;
+ border-radius:.5rem
+}
+@media (min-width:576px) {
+ .jumbotron {
+  padding:4rem 2rem
+ }
+}
+.jumbotron-fluid {
+ padding-right:0;
+ padding-left:0;
+ border-radius:0
+}
+.alert {
+ position:relative;
+ padding:.75rem 1.25rem;
+ margin-bottom:1rem;
+ border:1px solid transparent;
+ border-radius:.5rem
+}
+.alert-heading {
+ color:inherit
+}
+.alert-link {
+ font-weight:600
+}
+.alert-dismissible {
+ padding-right:4rem
+}
+.alert-dismissible .close {
+ position:absolute;
+ top:0;
+ right:0;
+ padding:.75rem 1.25rem;
+ color:inherit
+}
+.alert-primary {
+ color:#8e4420;
+ background-color:#fce0d2;
+ border-color:#fbd4c0
+}
+.alert-primary hr {
+ border-top-color:#f9c4a8
+}
+.alert-primary .alert-link {
+ color:#643017
+}
+.alert-secondary {
+ color:#10783b;
+ background-color:#ccf4dd;
+ border-color:#b8f0cf
+}
+.alert-secondary hr {
+ border-top-color:#a3ecc1
+}
+.alert-secondary .alert-link {
+ color:#0a4b25
+}
+.alert-success {
+ color:#45198e;
+ background-color:#e0cffc;
+ border-color:#d4bcfb
+}
+.alert-success hr {
+ border-top-color:#c5a4fa
+}
+.alert-success .alert-link {
+ color:#301163
+}
+.alert-info {
+ color:#105095;
+ background-color:#cce5ff;
+ border-color:#b8daff
+}
+.alert-info hr {
+ border-top-color:#9fcdff
+}
+.alert-info .alert-link {
+ color:#0b3767
+}
+.alert-warning {
+ color:#957514;
+ background-color:#fff3cd;
+ border-color:#ffeeba
+}
+.alert-warning hr {
+ border-top-color:#ffe8a1
+}
+.alert-warning .alert-link {
+ color:#68520e
+}
+.alert-danger {
+ color:#572b15;
+ background-color:#e7d6ce;
+ border-color:#ddc6ba
+}
+.alert-danger hr {
+ border-top-color:#d5b8a9
+}
+.alert-danger .alert-link {
+ color:#2e170b
+}
+.alert-light {
+ color:#919292;
+ background-color:#fefefe;
+ border-color:#fdfdfe
+}
+.alert-light hr {
+ border-top-color:#ececf6
+}
+.alert-light .alert-link {
+ color:#777979
+}
+.alert-dark {
+ color:#2b2e32;
+ background-color:#d6d8d9;
+ border-color:#c6c8ca
+}
+.alert-dark hr {
+ border-top-color:#b9bbbe
+}
+.alert-dark .alert-link {
+ color:#131517
+}
+@keyframes progress-bar-stripes {
+ from {
+  background-position:1rem 0
+ }
+ to {
+  background-position:0 0
+ }
+}
+.progress {
+ display:flex;
+ height:1rem;
+ overflow:hidden;
+ line-height:0;
+ font-size:.75rem;
+ background-color:#e9ecef;
+ border-radius:.5rem
+}
+.progress-bar {
+ display:flex;
+ flex-direction:column;
+ justify-content:center;
+ overflow:hidden;
+ color:#fff;
+ text-align:center;
+ white-space:nowrap;
+ background-color:#f1641e;
+ transition:width .6s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .progress-bar {
+  transition:none
+ }
+}
+.progress-bar-striped {
+ background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);
+ background-size:1rem 1rem
+}
+.progress-bar-animated {
+ animation:progress-bar-stripes 1s linear infinite
+}
+@media (prefers-reduced-motion:reduce) {
+ .progress-bar-animated {
+  animation:none
+ }
+}
+.media {
+ display:flex;
+ align-items:flex-start
+}
+.media-body {
+ flex:1
+}
+.list-group {
+ display:flex;
+ flex-direction:column;
+ padding-left:0;
+ margin-bottom:0;
+ border-radius:.5rem
+}
+.list-group-item-action {
+ width:100%;
+ color:#495057;
+ text-align:inherit
+}
+.list-group-item-action:focus,
+.list-group-item-action:hover {
+ z-index:1;
+ color:#495057;
+ text-decoration:none;
+ background-color:#f8f9fa
+}
+.list-group-item-action:active {
+ color:#495057;
+ background-color:#e9ecef
+}
+.list-group-item {
+ position:relative;
+ display:block;
+ padding:.75rem 1.25rem;
+ background-color:#fff;
+ border:1px solid rgba(34,34,34,.125)
+}
+.list-group-item:first-child {
+ border-top-left-radius:inherit;
+ border-top-right-radius:inherit
+}
+.list-group-item:last-child {
+ border-bottom-right-radius:inherit;
+ border-bottom-left-radius:inherit
+}
+.list-group-item.disabled,
+.list-group-item:disabled {
+ color:#6c757d;
+ pointer-events:none;
+ background-color:#fff
+}
+.list-group-item.active {
+ z-index:2;
+ color:#fff;
+ background-color:#f1641e;
+ border-color:#f1641e
+}
+.list-group-item+.list-group-item {
+ border-top-width:0
+}
+.list-group-item+.list-group-item.active {
+ margin-top:-1px;
+ border-top-width:1px
+}
+.list-group-horizontal {
+ flex-direction:row
+}
+.list-group-horizontal>.list-group-item:first-child {
+ border-bottom-left-radius:.5rem;
+ border-top-right-radius:0
+}
+.list-group-horizontal>.list-group-item:last-child {
+ border-top-right-radius:.5rem;
+ border-bottom-left-radius:0
+}
+.list-group-horizontal>.list-group-item.active {
+ margin-top:0
+}
+.list-group-horizontal>.list-group-item+.list-group-item {
+ border-top-width:1px;
+ border-left-width:0
+}
+.list-group-horizontal>.list-group-item+.list-group-item.active {
+ margin-left:-1px;
+ border-left-width:1px
+}
+@media (min-width:576px) {
+ .list-group-horizontal-sm {
+  flex-direction:row
+ }
+ .list-group-horizontal-sm>.list-group-item:first-child {
+  border-bottom-left-radius:.5rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-sm>.list-group-item:last-child {
+  border-top-right-radius:.5rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-sm>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-sm>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-sm>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+@media (min-width:768px) {
+ .list-group-horizontal-md {
+  flex-direction:row
+ }
+ .list-group-horizontal-md>.list-group-item:first-child {
+  border-bottom-left-radius:.5rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-md>.list-group-item:last-child {
+  border-top-right-radius:.5rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-md>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-md>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-md>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+@media (min-width:992px) {
+ .list-group-horizontal-lg {
+  flex-direction:row
+ }
+ .list-group-horizontal-lg>.list-group-item:first-child {
+  border-bottom-left-radius:.5rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-lg>.list-group-item:last-child {
+  border-top-right-radius:.5rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-lg>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-lg>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-lg>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+@media (min-width:1200px) {
+ .list-group-horizontal-xl {
+  flex-direction:row
+ }
+ .list-group-horizontal-xl>.list-group-item:first-child {
+  border-bottom-left-radius:.5rem;
+  border-top-right-radius:0
+ }
+ .list-group-horizontal-xl>.list-group-item:last-child {
+  border-top-right-radius:.5rem;
+  border-bottom-left-radius:0
+ }
+ .list-group-horizontal-xl>.list-group-item.active {
+  margin-top:0
+ }
+ .list-group-horizontal-xl>.list-group-item+.list-group-item {
+  border-top-width:1px;
+  border-left-width:0
+ }
+ .list-group-horizontal-xl>.list-group-item+.list-group-item.active {
+  margin-left:-1px;
+  border-left-width:1px
+ }
+}
+.list-group-flush {
+ border-radius:0
+}
+.list-group-flush>.list-group-item {
+ border-width:0 0 1px
+}
+.list-group-flush>.list-group-item:last-child {
+ border-bottom-width:0
+}
+.list-group-item-primary {
+ color:#8e4420;
+ background-color:#fbd4c0
+}
+.list-group-item-primary.list-group-item-action:focus,
+.list-group-item-primary.list-group-item-action:hover {
+ color:#8e4420;
+ background-color:#f9c4a8
+}
+.list-group-item-primary.list-group-item-action.active {
+ color:#fff;
+ background-color:#8e4420;
+ border-color:#8e4420
+}
+.list-group-item-secondary {
+ color:#10783b;
+ background-color:#b8f0cf
+}
+.list-group-item-secondary.list-group-item-action:focus,
+.list-group-item-secondary.list-group-item-action:hover {
+ color:#10783b;
+ background-color:#a3ecc1
+}
+.list-group-item-secondary.list-group-item-action.active {
+ color:#fff;
+ background-color:#10783b;
+ border-color:#10783b
+}
+.list-group-item-success {
+ color:#45198e;
+ background-color:#d4bcfb
+}
+.list-group-item-success.list-group-item-action:focus,
+.list-group-item-success.list-group-item-action:hover {
+ color:#45198e;
+ background-color:#c5a4fa
+}
+.list-group-item-success.list-group-item-action.active {
+ color:#fff;
+ background-color:#45198e;
+ border-color:#45198e
+}
+.list-group-item-info {
+ color:#105095;
+ background-color:#b8daff
+}
+.list-group-item-info.list-group-item-action:focus,
+.list-group-item-info.list-group-item-action:hover {
+ color:#105095;
+ background-color:#9fcdff
+}
+.list-group-item-info.list-group-item-action.active {
+ color:#fff;
+ background-color:#105095;
+ border-color:#105095
+}
+.list-group-item-warning {
+ color:#957514;
+ background-color:#ffeeba
+}
+.list-group-item-warning.list-group-item-action:focus,
+.list-group-item-warning.list-group-item-action:hover {
+ color:#957514;
+ background-color:#ffe8a1
+}
+.list-group-item-warning.list-group-item-action.active {
+ color:#fff;
+ background-color:#957514;
+ border-color:#957514
+}
+.list-group-item-danger {
+ color:#572b15;
+ background-color:#ddc6ba
+}
+.list-group-item-danger.list-group-item-action:focus,
+.list-group-item-danger.list-group-item-action:hover {
+ color:#572b15;
+ background-color:#d5b8a9
+}
+.list-group-item-danger.list-group-item-action.active {
+ color:#fff;
+ background-color:#572b15;
+ border-color:#572b15
+}
+.list-group-item-light {
+ color:#919292;
+ background-color:#fdfdfe
+}
+.list-group-item-light.list-group-item-action:focus,
+.list-group-item-light.list-group-item-action:hover {
+ color:#919292;
+ background-color:#ececf6
+}
+.list-group-item-light.list-group-item-action.active {
+ color:#fff;
+ background-color:#919292;
+ border-color:#919292
+}
+.list-group-item-dark {
+ color:#2b2e32;
+ background-color:#c6c8ca
+}
+.list-group-item-dark.list-group-item-action:focus,
+.list-group-item-dark.list-group-item-action:hover {
+ color:#2b2e32;
+ background-color:#b9bbbe
+}
+.list-group-item-dark.list-group-item-action.active {
+ color:#fff;
+ background-color:#2b2e32;
+ border-color:#2b2e32
+}
+.close {
+ float:right;
+ font-size:1.5rem;
+ font-weight:600;
+ line-height:1;
+ color:#222;
+ text-shadow:0 1px 0 #fff;
+ opacity:.5
+}
+.close:hover {
+ color:#222;
+ text-decoration:none
+}
+.close:not(:disabled):not(.disabled):focus,
+.close:not(:disabled):not(.disabled):hover {
+ opacity:.75
+}
+button.close {
+ padding:0;
+ background-color:transparent;
+ border:0
+}
+a.close.disabled {
+ pointer-events:none
+}
+.toast {
+ max-width:350px;
+ overflow:hidden;
+ font-size:.875rem;
+ background-color:rgba(255,255,255,.85);
+ background-clip:padding-box;
+ border:1px solid rgba(0,0,0,.1);
+ box-shadow:0 .25rem .75rem rgba(34,34,34,.1);
+ backdrop-filter:blur(10px);
+ opacity:0;
+ border-radius:.25rem
+}
+.toast:not(:last-child) {
+ margin-bottom:.75rem
+}
+.toast.showing {
+ opacity:1
+}
+.toast.show {
+ display:block;
+ opacity:1
+}
+.toast.hide {
+ display:none
+}
+.toast-header {
+ display:flex;
+ align-items:center;
+ padding:.25rem .75rem;
+ color:#6c757d;
+ background-color:rgba(255,255,255,.85);
+ background-clip:padding-box;
+ border-bottom:1px solid rgba(0,0,0,.05)
+}
+.toast-body {
+ padding:.75rem
+}
+.modal-open {
+ overflow:hidden
+}
+.modal-open .modal {
+ overflow-x:hidden;
+ overflow-y:auto
+}
+.modal {
+ position:fixed;
+ top:0;
+ left:0;
+ z-index:1050;
+ display:none;
+ width:100%;
+ height:100%;
+ overflow:hidden;
+ outline:0
+}
+.modal-dialog {
+ position:relative;
+ width:auto;
+ margin:.5rem;
+ pointer-events:none
+}
+.modal.fade .modal-dialog {
+ transition:transform .3s ease-out;
+ transform:translate(0,-50px)
+}
+@media (prefers-reduced-motion:reduce) {
+ .modal.fade .modal-dialog {
+  transition:none
+ }
+}
+.modal.show .modal-dialog {
+ transform:none
+}
+.modal.modal-static .modal-dialog {
+ transform:scale(1.02)
+}
+.modal-dialog-scrollable {
+ display:flex;
+ max-height:calc(100% - 1rem)
+}
+.modal-dialog-scrollable .modal-content {
+ max-height:calc(100vh - 1rem);
+ overflow:hidden
+}
+.modal-dialog-scrollable .modal-footer,
+.modal-dialog-scrollable .modal-header {
+ flex-shrink:0
+}
+.modal-dialog-scrollable .modal-body {
+ overflow-y:auto
+}
+.modal-dialog-centered {
+ display:flex;
+ align-items:center;
+ min-height:calc(100% - 1rem)
+}
+.modal-dialog-centered::before {
+ display:block;
+ height:calc(100vh - 1rem);
+ height:min-content;
+ content:""
+}
+.modal-dialog-centered.modal-dialog-scrollable {
+ flex-direction:column;
+ justify-content:center;
+ height:100%
+}
+.modal-dialog-centered.modal-dialog-scrollable .modal-content {
+ max-height:none
+}
+.modal-dialog-centered.modal-dialog-scrollable::before {
+ content:none
+}
+.modal-content {
+ position:relative;
+ display:flex;
+ flex-direction:column;
+ width:100%;
+ pointer-events:auto;
+ background-color:#fff;
+ background-clip:padding-box;
+ border:1px solid rgba(34,34,34,.2);
+ border-radius:.5rem;
+ outline:0
+}
+.modal-backdrop {
+ position:fixed;
+ top:0;
+ left:0;
+ z-index:1040;
+ width:100vw;
+ height:100vh;
+ background-color:#222
+}
+.modal-backdrop.fade {
+ opacity:0
+}
+.modal-backdrop.show {
+ opacity:.5
+}
+.modal-header {
+ display:flex;
+ align-items:flex-start;
+ justify-content:space-between;
+ padding:1rem 1rem;
+ border-bottom:1px solid #495057;
+ border-top-left-radius:calc(.5rem - 1px);
+ border-top-right-radius:calc(.5rem - 1px)
+}
+.modal-header .close {
+ padding:1rem 1rem;
+ margin:-1rem -1rem -1rem auto
+}
+.modal-title {
+ margin-bottom:0;
+ line-height:1.5
+}
+.modal-body {
+ position:relative;
+ flex:1 1 auto;
+ padding:1rem
+}
+.modal-footer {
+ display:flex;
+ flex-wrap:wrap;
+ align-items:center;
+ justify-content:flex-end;
+ padding:.75rem;
+ border-top:1px solid #495057;
+ border-bottom-right-radius:calc(.5rem - 1px);
+ border-bottom-left-radius:calc(.5rem - 1px)
+}
+.modal-footer>* {
+ margin:.25rem
+}
+.modal-scrollbar-measure {
+ position:absolute;
+ top:-9999px;
+ width:50px;
+ height:50px;
+ overflow:scroll
+}
+@media (min-width:576px) {
+ .modal-dialog {
+  max-width:500px;
+  margin:1.75rem auto
+ }
+ .modal-dialog-scrollable {
+  max-height:calc(100% - 3.5rem)
+ }
+ .modal-dialog-scrollable .modal-content {
+  max-height:calc(100vh - 3.5rem)
+ }
+ .modal-dialog-centered {
+  min-height:calc(100% - 3.5rem)
+ }
+ .modal-dialog-centered::before {
+  height:calc(100vh - 3.5rem);
+  height:min-content
+ }
+ .modal-sm {
+  max-width:300px
+ }
+}
+@media (min-width:992px) {
+ .modal-lg,
+ .modal-xl {
+  max-width:800px
+ }
+}
+@media (min-width:1200px) {
+ .modal-xl {
+  max-width:1140px
+ }
+}
+.tooltip {
+ position:absolute;
+ z-index:1070;
+ display:block;
+ margin:0;
+ font-family:-apple-system,BlinkMacSystemFont,"Droid Sans","Segoe UI",Helvetica,Arial,sans-serif;
+ font-style:normal;
+ font-weight:400;
+ line-height:1.5;
+ text-align:left;
+ text-align:start;
+ text-decoration:none;
+ text-shadow:none;
+ text-transform:none;
+ letter-spacing:normal;
+ word-break:normal;
+ word-spacing:normal;
+ white-space:normal;
+ line-break:auto;
+ font-size:.875rem;
+ word-wrap:break-word;
+ opacity:0
+}
+.tooltip.show {
+ opacity:.9
+}
+.tooltip .arrow {
+ position:absolute;
+ display:block;
+ width:.8rem;
+ height:.4rem
+}
+.tooltip .arrow::before {
+ position:absolute;
+ content:"";
+ border-color:transparent;
+ border-style:solid
+}
+.bs-tooltip-auto[x-placement^=top],
+.bs-tooltip-top {
+ padding:.4rem 0
+}
+.bs-tooltip-auto[x-placement^=top] .arrow,
+.bs-tooltip-top .arrow {
+ bottom:0
+}
+.bs-tooltip-auto[x-placement^=top] .arrow::before,
+.bs-tooltip-top .arrow::before {
+ top:0;
+ border-width:.4rem .4rem 0;
+ border-top-color:#222
+}
+.bs-tooltip-auto[x-placement^=right],
+.bs-tooltip-right {
+ padding:0 .4rem
+}
+.bs-tooltip-auto[x-placement^=right] .arrow,
+.bs-tooltip-right .arrow {
+ left:0;
+ width:.4rem;
+ height:.8rem
+}
+.bs-tooltip-auto[x-placement^=right] .arrow::before,
+.bs-tooltip-right .arrow::before {
+ right:0;
+ border-width:.4rem .4rem .4rem 0;
+ border-right-color:#222
+}
+.bs-tooltip-auto[x-placement^=bottom],
+.bs-tooltip-bottom {
+ padding:.4rem 0
+}
+.bs-tooltip-auto[x-placement^=bottom] .arrow,
+.bs-tooltip-bottom .arrow {
+ top:0
+}
+.bs-tooltip-auto[x-placement^=bottom] .arrow::before,
+.bs-tooltip-bottom .arrow::before {
+ bottom:0;
+ border-width:0 .4rem .4rem;
+ border-bottom-color:#222
+}
+.bs-tooltip-auto[x-placement^=left],
+.bs-tooltip-left {
+ padding:0 .4rem
+}
+.bs-tooltip-auto[x-placement^=left] .arrow,
+.bs-tooltip-left .arrow {
+ right:0;
+ width:.4rem;
+ height:.8rem
+}
+.bs-tooltip-auto[x-placement^=left] .arrow::before,
+.bs-tooltip-left .arrow::before {
+ left:0;
+ border-width:.4rem 0 .4rem .4rem;
+ border-left-color:#222
+}
+.tooltip-inner {
+ max-width:200px;
+ padding:.25rem .5rem;
+ color:#fff;
+ text-align:center;
+ background-color:#222;
+ border-radius:.5rem
+}
+.popover {
+ position:absolute;
+ top:0;
+ left:0;
+ z-index:1060;
+ display:block;
+ max-width:276px;
+ font-family:-apple-system,BlinkMacSystemFont,"Droid Sans","Segoe UI",Helvetica,Arial,sans-serif;
+ font-style:normal;
+ font-weight:400;
+ line-height:1.5;
+ text-align:left;
+ text-align:start;
+ text-decoration:none;
+ text-shadow:none;
+ text-transform:none;
+ letter-spacing:normal;
+ word-break:normal;
+ word-spacing:normal;
+ white-space:normal;
+ line-break:auto;
+ font-size:.875rem;
+ word-wrap:break-word;
+ background-color:#fff;
+ background-clip:padding-box;
+ border:1px solid rgba(34,34,34,.2);
+ border-radius:.5rem
+}
+.popover .arrow {
+ position:absolute;
+ display:block;
+ width:1rem;
+ height:.5rem;
+ margin:0 .5rem
+}
+.popover .arrow::after,
+.popover .arrow::before {
+ position:absolute;
+ display:block;
+ content:"";
+ border-color:transparent;
+ border-style:solid
+}
+.bs-popover-auto[x-placement^=top],
+.bs-popover-top {
+ margin-bottom:.5rem
+}
+.bs-popover-auto[x-placement^=top]>.arrow,
+.bs-popover-top>.arrow {
+ bottom:calc(-.5rem - 1px)
+}
+.bs-popover-auto[x-placement^=top]>.arrow::before,
+.bs-popover-top>.arrow::before {
+ bottom:0;
+ border-width:.5rem .5rem 0;
+ border-top-color:rgba(34,34,34,.25)
+}
+.bs-popover-auto[x-placement^=top]>.arrow::after,
+.bs-popover-top>.arrow::after {
+ bottom:1px;
+ border-width:.5rem .5rem 0;
+ border-top-color:#fff
+}
+.bs-popover-auto[x-placement^=right],
+.bs-popover-right {
+ margin-left:.5rem
+}
+.bs-popover-auto[x-placement^=right]>.arrow,
+.bs-popover-right>.arrow {
+ left:calc(-.5rem - 1px);
+ width:.5rem;
+ height:1rem;
+ margin:.5rem 0
+}
+.bs-popover-auto[x-placement^=right]>.arrow::before,
+.bs-popover-right>.arrow::before {
+ left:0;
+ border-width:.5rem .5rem .5rem 0;
+ border-right-color:rgba(34,34,34,.25)
+}
+.bs-popover-auto[x-placement^=right]>.arrow::after,
+.bs-popover-right>.arrow::after {
+ left:1px;
+ border-width:.5rem .5rem .5rem 0;
+ border-right-color:#fff
+}
+.bs-popover-auto[x-placement^=bottom],
+.bs-popover-bottom {
+ margin-top:.5rem
+}
+.bs-popover-auto[x-placement^=bottom]>.arrow,
+.bs-popover-bottom>.arrow {
+ top:calc(-.5rem - 1px)
+}
+.bs-popover-auto[x-placement^=bottom]>.arrow::before,
+.bs-popover-bottom>.arrow::before {
+ top:0;
+ border-width:0 .5rem .5rem .5rem;
+ border-bottom-color:rgba(34,34,34,.25)
+}
+.bs-popover-auto[x-placement^=bottom]>.arrow::after,
+.bs-popover-bottom>.arrow::after {
+ top:1px;
+ border-width:0 .5rem .5rem .5rem;
+ border-bottom-color:#fff
+}
+.bs-popover-auto[x-placement^=bottom] .popover-header::before,
+.bs-popover-bottom .popover-header::before {
+ position:absolute;
+ top:0;
+ left:50%;
+ display:block;
+ width:1rem;
+ margin-left:-.5rem;
+ content:"";
+ border-bottom:1px solid #f7f7f7
+}
+.bs-popover-auto[x-placement^=left],
+.bs-popover-left {
+ margin-right:.5rem
+}
+.bs-popover-auto[x-placement^=left]>.arrow,
+.bs-popover-left>.arrow {
+ right:calc(-.5rem - 1px);
+ width:.5rem;
+ height:1rem;
+ margin:.5rem 0
+}
+.bs-popover-auto[x-placement^=left]>.arrow::before,
+.bs-popover-left>.arrow::before {
+ right:0;
+ border-width:.5rem 0 .5rem .5rem;
+ border-left-color:rgba(34,34,34,.25)
+}
+.bs-popover-auto[x-placement^=left]>.arrow::after,
+.bs-popover-left>.arrow::after {
+ right:1px;
+ border-width:.5rem 0 .5rem .5rem;
+ border-left-color:#fff
+}
+.popover-header {
+ padding:.5rem .75rem;
+ margin-bottom:0;
+ font-size:1rem;
+ color:#495057;
+ background-color:#f7f7f7;
+ border-bottom:1px solid #ebebeb;
+ border-top-left-radius:calc(.5rem - 1px);
+ border-top-right-radius:calc(.5rem - 1px)
+}
+.popover-header:empty {
+ display:none
+}
+.popover-body {
+ padding:.5rem .75rem;
+ color:#495057
+}
+.carousel {
+ position:relative
+}
+.carousel.pointer-event {
+ touch-action:pan-y
+}
+.carousel-inner {
+ position:relative;
+ width:100%;
+ overflow:hidden
+}
+.carousel-inner::after {
+ display:block;
+ clear:both;
+ content:""
+}
+.carousel-item {
+ position:relative;
+ display:none;
+ float:left;
+ width:100%;
+ margin-right:-100%;
+ backface-visibility:hidden;
+ transition:transform .6s ease-in-out
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-item {
+  transition:none
+ }
+}
+.carousel-item-next,
+.carousel-item-prev,
+.carousel-item.active {
+ display:block
+}
+.active.carousel-item-right,
+.carousel-item-next:not(.carousel-item-left) {
+ transform:translateX(100%)
+}
+.active.carousel-item-left,
+.carousel-item-prev:not(.carousel-item-right) {
+ transform:translateX(-100%)
+}
+.carousel-fade .carousel-item {
+ opacity:0;
+ transition-property:opacity;
+ transform:none
+}
+.carousel-fade .carousel-item-next.carousel-item-left,
+.carousel-fade .carousel-item-prev.carousel-item-right,
+.carousel-fade .carousel-item.active {
+ z-index:1;
+ opacity:1
+}
+.carousel-fade .active.carousel-item-left,
+.carousel-fade .active.carousel-item-right {
+ z-index:0;
+ opacity:0;
+ transition:opacity 0s .6s
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-fade .active.carousel-item-left,
+ .carousel-fade .active.carousel-item-right {
+  transition:none
+ }
+}
+.carousel-control-next,
+.carousel-control-prev {
+ position:absolute;
+ top:0;
+ bottom:0;
+ z-index:1;
+ display:flex;
+ align-items:center;
+ justify-content:center;
+ width:15%;
+ color:#fff;
+ text-align:center;
+ opacity:.5;
+ transition:opacity .15s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-control-next,
+ .carousel-control-prev {
+  transition:none
+ }
+}
+.carousel-control-next:focus,
+.carousel-control-next:hover,
+.carousel-control-prev:focus,
+.carousel-control-prev:hover {
+ color:#fff;
+ text-decoration:none;
+ outline:0;
+ opacity:.9
+}
+.carousel-control-prev {
+ left:0
+}
+.carousel-control-next {
+ right:0
+}
+.carousel-control-next-icon,
+.carousel-control-prev-icon {
+ display:inline-block;
+ width:20px;
+ height:20px;
+ background:no-repeat 50%/100% 100%
+}
+.carousel-control-prev-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")
+}
+.carousel-control-next-icon {
+ background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")
+}
+.carousel-indicators {
+ position:absolute;
+ right:0;
+ bottom:0;
+ left:0;
+ z-index:15;
+ display:flex;
+ justify-content:center;
+ padding-left:0;
+ margin-right:15%;
+ margin-left:15%;
+ list-style:none
+}
+.carousel-indicators li {
+ box-sizing:content-box;
+ flex:0 1 auto;
+ width:30px;
+ height:3px;
+ margin-right:3px;
+ margin-left:3px;
+ text-indent:-999px;
+ cursor:pointer;
+ background-color:#fff;
+ background-clip:padding-box;
+ border-top:10px solid transparent;
+ border-bottom:10px solid transparent;
+ opacity:.5;
+ transition:opacity .6s ease
+}
+@media (prefers-reduced-motion:reduce) {
+ .carousel-indicators li {
+  transition:none
+ }
+}
+.carousel-indicators .active {
+ opacity:1
+}
+.carousel-caption {
+ position:absolute;
+ right:15%;
+ bottom:20px;
+ left:15%;
+ z-index:10;
+ padding-top:20px;
+ padding-bottom:20px;
+ color:#fff;
+ text-align:center
+}
+@keyframes spinner-border {
+ to {
+  transform:rotate(360deg)
+ }
+}
+.spinner-border {
+ display:inline-block;
+ width:2rem;
+ height:2rem;
+ vertical-align:text-bottom;
+ border:.25em solid currentColor;
+ border-right-color:transparent;
+ border-radius:50%;
+ animation:spinner-border .75s linear infinite
+}
+.spinner-border-sm {
+ width:1rem;
+ height:1rem;
+ border-width:.2em
+}
+@keyframes spinner-grow {
+ 0% {
+  transform:scale(0)
+ }
+ 50% {
+  opacity:1;
+  transform:none
+ }
+}
+.spinner-grow {
+ display:inline-block;
+ width:2rem;
+ height:2rem;
+ vertical-align:text-bottom;
+ background-color:currentColor;
+ border-radius:50%;
+ opacity:0;
+ animation:spinner-grow .75s linear infinite
+}
+.spinner-grow-sm {
+ width:1rem;
+ height:1rem
+}
+.align-baseline {
+ vertical-align:baseline!important
+}
+.align-top {
+ vertical-align:top!important
+}
+.align-middle {
+ vertical-align:middle!important
+}
+.align-bottom {
+ vertical-align:bottom!important
+}
+.align-text-bottom {
+ vertical-align:text-bottom!important
+}
+.align-text-top {
+ vertical-align:text-top!important
+}
+.bg-primary {
+ background-color:#f1641e!important
+}
+a.bg-primary:focus,
+a.bg-primary:hover,
+button.bg-primary:focus,
+button.bg-primary:hover {
+ background-color:#cf4d0d!important
+}
+.bg-secondary {
+ background-color:#00c853!important
+}
+a.bg-secondary:focus,
+a.bg-secondary:hover,
+button.bg-secondary:focus,
+button.bg-secondary:hover {
+ background-color:#00953e!important
+}
+.bg-success {
+ background-color:#6610f2!important
+}
+a.bg-success:focus,
+a.bg-success:hover,
+button.bg-success:focus,
+button.bg-success:hover {
+ background-color:#510bc4!important
+}
+.bg-info {
+ background-color:#007bff!important
+}
+a.bg-info:focus,
+a.bg-info:hover,
+button.bg-info:focus,
+button.bg-info:hover {
+ background-color:#0062cc!important
+}
+.bg-warning {
+ background-color:#ffc107!important
+}
+a.bg-warning:focus,
+a.bg-warning:hover,
+button.bg-warning:focus,
+button.bg-warning:hover {
+ background-color:#d39e00!important
+}
+.bg-danger {
+ background-color:#873208!important
+}
+a.bg-danger:focus,
+a.bg-danger:hover,
+button.bg-danger:focus,
+button.bg-danger:hover {
+ background-color:#572105!important
+}
+.bg-light {
+ background-color:#f8f9fa!important
+}
+a.bg-light:focus,
+a.bg-light:hover,
+button.bg-light:focus,
+button.bg-light:hover {
+ background-color:#dae0e5!important
+}
+.bg-dark {
+ background-color:#343a40!important
+}
+a.bg-dark:focus,
+a.bg-dark:hover,
+button.bg-dark:focus,
+button.bg-dark:hover {
+ background-color:#1d2124!important
+}
+.bg-white {
+ background-color:#fff!important
+}
+.bg-transparent {
+ background-color:transparent!important
+}
+.border {
+ border:1px solid #495057!important
+}
+.border-top {
+ border-top:1px solid #495057!important
+}
+.border-right {
+ border-right:1px solid #495057!important
+}
+.border-bottom {
+ border-bottom:1px solid #495057!important
+}
+.border-left {
+ border-left:1px solid #495057!important
+}
+.border-0 {
+ border:0!important
+}
+.border-top-0 {
+ border-top:0!important
+}
+.border-right-0 {
+ border-right:0!important
+}
+.border-bottom-0 {
+ border-bottom:0!important
+}
+.border-left-0 {
+ border-left:0!important
+}
+.border-primary {
+ border-color:#f1641e!important
+}
+.border-secondary {
+ border-color:#c80000 !important;
+}
+.border-success {
+ border-color:#6610f2!important
+}
+.border-info {
+ border-color:#007bff!important
+}
+.border-warning {
+ border-color:#ffc107!important
+}
+.border-danger {
+ border-color:#873208!important
+}
+.border-light {
+ border-color:#f8f9fa!important
+}
+.border-dark {
+ border-color:#343a40!important
+}
+.border-white {
+ border-color:#fff!important
+}
+.rounded-sm {
+ border-radius:1rem!important
+}
+.rounded {
+ border-radius:.5rem!important
+}
+.rounded-top {
+ border-top-left-radius:.5rem!important;
+ border-top-right-radius:.5rem!important
+}
+.rounded-right {
+ border-top-right-radius:.5rem!important;
+ border-bottom-right-radius:.5rem!important
+}
+.rounded-bottom {
+ border-bottom-right-radius:.5rem!important;
+ border-bottom-left-radius:.5rem!important
+}
+.rounded-left {
+ border-top-left-radius:.5rem!important;
+ border-bottom-left-radius:.5rem!important
+}
+.rounded-lg {
+ border-radius:.5rem!important
+}
+.rounded-circle {
+ border-radius:50%!important
+}
+.rounded-pill {
+ border-radius:.25rem!important
+}
+.rounded-0 {
+ border-radius:0!important
+}
+.clearfix::after {
+ display:block;
+ clear:both;
+ content:""
+}
+.d-none {
+ display:none!important
+}
+.d-inline {
+ display:inline!important
+}
+.d-inline-block {
+ display:inline-block!important
+}
+.d-block {
+ display:block!important
+}
+.d-table {
+ display:table!important
+}
+.d-table-row {
+ display:table-row!important
+}
+.d-table-cell {
+ display:table-cell!important
+}
+.d-flex {
+ display:flex!important
+}
+.d-inline-flex {
+ display:inline-flex!important
+}
+@media (min-width:576px) {
+ .d-sm-none {
+  display:none!important
+ }
+ .d-sm-inline {
+  display:inline!important
+ }
+ .d-sm-inline-block {
+  display:inline-block!important
+ }
+ .d-sm-block {
+  display:block!important
+ }
+ .d-sm-table {
+  display:table!important
+ }
+ .d-sm-table-row {
+  display:table-row!important
+ }
+ .d-sm-table-cell {
+  display:table-cell!important
+ }
+ .d-sm-flex {
+  display:flex!important
+ }
+ .d-sm-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media (min-width:768px) {
+ .d-md-none {
+  display:none!important
+ }
+ .d-md-inline {
+  display:inline!important
+ }
+ .d-md-inline-block {
+  display:inline-block!important
+ }
+ .d-md-block {
+  display:block!important
+ }
+ .d-md-table {
+  display:table!important
+ }
+ .d-md-table-row {
+  display:table-row!important
+ }
+ .d-md-table-cell {
+  display:table-cell!important
+ }
+ .d-md-flex {
+  display:flex!important
+ }
+ .d-md-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media (min-width:992px) {
+ .d-lg-none {
+  display:none!important
+ }
+ .d-lg-inline {
+  display:inline!important
+ }
+ .d-lg-inline-block {
+  display:inline-block!important
+ }
+ .d-lg-block {
+  display:block!important
+ }
+ .d-lg-table {
+  display:table!important
+ }
+ .d-lg-table-row {
+  display:table-row!important
+ }
+ .d-lg-table-cell {
+  display:table-cell!important
+ }
+ .d-lg-flex {
+  display:flex!important
+ }
+ .d-lg-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media (min-width:1200px) {
+ .d-xl-none {
+  display:none!important
+ }
+ .d-xl-inline {
+  display:inline!important
+ }
+ .d-xl-inline-block {
+  display:inline-block!important
+ }
+ .d-xl-block {
+  display:block!important
+ }
+ .d-xl-table {
+  display:table!important
+ }
+ .d-xl-table-row {
+  display:table-row!important
+ }
+ .d-xl-table-cell {
+  display:table-cell!important
+ }
+ .d-xl-flex {
+  display:flex!important
+ }
+ .d-xl-inline-flex {
+  display:inline-flex!important
+ }
+}
+@media print {
+ .d-print-none {
+  display:none!important
+ }
+ .d-print-inline {
+  display:inline!important
+ }
+ .d-print-inline-block {
+  display:inline-block!important
+ }
+ .d-print-block {
+  display:block!important
+ }
+ .d-print-table {
+  display:table!important
+ }
+ .d-print-table-row {
+  display:table-row!important
+ }
+ .d-print-table-cell {
+  display:table-cell!important
+ }
+ .d-print-flex {
+  display:flex!important
+ }
+ .d-print-inline-flex {
+  display:inline-flex!important
+ }
+}
+.embed-responsive {
+ position:relative;
+ display:block;
+ width:100%;
+ padding:0;
+ overflow:hidden
+}
+.embed-responsive::before {
+ display:block;
+ content:""
+}
+.embed-responsive .embed-responsive-item,
+.embed-responsive embed,
+.embed-responsive iframe,
+.embed-responsive object,
+.embed-responsive video {
+ position:absolute;
+ top:0;
+ bottom:0;
+ left:0;
+ width:100%;
+ height:100%;
+ border:0
+}
+.embed-responsive-21by9::before {
+ padding-top:42.85714%
+}
+.embed-responsive-16by9::before {
+ padding-top:56.25%
+}
+.embed-responsive-4by3::before {
+ padding-top:75%
+}
+.embed-responsive-1by1::before {
+ padding-top:100%
+}
+.flex-row {
+ flex-direction:row!important
+}
+.flex-column {
+ flex-direction:column!important
+}
+.flex-row-reverse {
+ flex-direction:row-reverse!important
+}
+.flex-column-reverse {
+ flex-direction:column-reverse!important
+}
+.flex-wrap {
+ flex-wrap:wrap!important
+}
+.flex-nowrap {
+ flex-wrap:nowrap!important
+}
+.flex-wrap-reverse {
+ flex-wrap:wrap-reverse!important
+}
+.flex-fill {
+ flex:1 1 auto!important
+}
+.flex-grow-0 {
+ flex-grow:0!important
+}
+.flex-grow-1 {
+ flex-grow:1!important
+}
+.flex-shrink-0 {
+ flex-shrink:0!important
+}
+.flex-shrink-1 {
+ flex-shrink:1!important
+}
+.justify-content-start {
+ justify-content:flex-start!important
+}
+.justify-content-end {
+ justify-content:flex-end!important
+}
+.justify-content-center {
+ justify-content:center!important
+}
+.justify-content-between {
+ justify-content:space-between!important
+}
+.justify-content-around {
+ justify-content:space-around!important
+}
+.align-items-start {
+ align-items:flex-start!important
+}
+.align-items-end {
+ align-items:flex-end!important
+}
+.align-items-center {
+ align-items:center!important
+}
+.align-items-baseline {
+ align-items:baseline!important
+}
+.align-items-stretch {
+ align-items:stretch!important
+}
+.align-content-start {
+ align-content:flex-start!important
+}
+.align-content-end {
+ align-content:flex-end!important
+}
+.align-content-center {
+ align-content:center!important
+}
+.align-content-between {
+ align-content:space-between!important
+}
+.align-content-around {
+ align-content:space-around!important
+}
+.align-content-stretch {
+ align-content:stretch!important
+}
+.align-self-auto {
+ align-self:auto!important
+}
+.align-self-start {
+ align-self:flex-start!important
+}
+.align-self-end {
+ align-self:flex-end!important
+}
+.align-self-center {
+ align-self:center!important
+}
+.align-self-baseline {
+ align-self:baseline!important
+}
+.align-self-stretch {
+ align-self:stretch!important
+}
+@media (min-width:576px) {
+ .flex-sm-row {
+  flex-direction:row!important
+ }
+ .flex-sm-column {
+  flex-direction:column!important
+ }
+ .flex-sm-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-sm-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-sm-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-sm-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-sm-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-sm-fill {
+  flex:1 1 auto!important
+ }
+ .flex-sm-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-sm-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-sm-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-sm-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-sm-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-sm-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-sm-center {
+  justify-content:center!important
+ }
+ .justify-content-sm-between {
+  justify-content:space-between!important
+ }
+ .justify-content-sm-around {
+  justify-content:space-around!important
+ }
+ .align-items-sm-start {
+  align-items:flex-start!important
+ }
+ .align-items-sm-end {
+  align-items:flex-end!important
+ }
+ .align-items-sm-center {
+  align-items:center!important
+ }
+ .align-items-sm-baseline {
+  align-items:baseline!important
+ }
+ .align-items-sm-stretch {
+  align-items:stretch!important
+ }
+ .align-content-sm-start {
+  align-content:flex-start!important
+ }
+ .align-content-sm-end {
+  align-content:flex-end!important
+ }
+ .align-content-sm-center {
+  align-content:center!important
+ }
+ .align-content-sm-between {
+  align-content:space-between!important
+ }
+ .align-content-sm-around {
+  align-content:space-around!important
+ }
+ .align-content-sm-stretch {
+  align-content:stretch!important
+ }
+ .align-self-sm-auto {
+  align-self:auto!important
+ }
+ .align-self-sm-start {
+  align-self:flex-start!important
+ }
+ .align-self-sm-end {
+  align-self:flex-end!important
+ }
+ .align-self-sm-center {
+  align-self:center!important
+ }
+ .align-self-sm-baseline {
+  align-self:baseline!important
+ }
+ .align-self-sm-stretch {
+  align-self:stretch!important
+ }
+}
+@media (min-width:768px) {
+ .flex-md-row {
+  flex-direction:row!important
+ }
+ .flex-md-column {
+  flex-direction:column!important
+ }
+ .flex-md-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-md-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-md-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-md-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-md-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-md-fill {
+  flex:1 1 auto!important
+ }
+ .flex-md-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-md-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-md-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-md-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-md-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-md-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-md-center {
+  justify-content:center!important
+ }
+ .justify-content-md-between {
+  justify-content:space-between!important
+ }
+ .justify-content-md-around {
+  justify-content:space-around!important
+ }
+ .align-items-md-start {
+  align-items:flex-start!important
+ }
+ .align-items-md-end {
+  align-items:flex-end!important
+ }
+ .align-items-md-center {
+  align-items:center!important
+ }
+ .align-items-md-baseline {
+  align-items:baseline!important
+ }
+ .align-items-md-stretch {
+  align-items:stretch!important
+ }
+ .align-content-md-start {
+  align-content:flex-start!important
+ }
+ .align-content-md-end {
+  align-content:flex-end!important
+ }
+ .align-content-md-center {
+  align-content:center!important
+ }
+ .align-content-md-between {
+  align-content:space-between!important
+ }
+ .align-content-md-around {
+  align-content:space-around!important
+ }
+ .align-content-md-stretch {
+  align-content:stretch!important
+ }
+ .align-self-md-auto {
+  align-self:auto!important
+ }
+ .align-self-md-start {
+  align-self:flex-start!important
+ }
+ .align-self-md-end {
+  align-self:flex-end!important
+ }
+ .align-self-md-center {
+  align-self:center!important
+ }
+ .align-self-md-baseline {
+  align-self:baseline!important
+ }
+ .align-self-md-stretch {
+  align-self:stretch!important
+ }
+}
+@media (min-width:992px) {
+ .flex-lg-row {
+  flex-direction:row!important
+ }
+ .flex-lg-column {
+  flex-direction:column!important
+ }
+ .flex-lg-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-lg-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-lg-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-lg-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-lg-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-lg-fill {
+  flex:1 1 auto!important
+ }
+ .flex-lg-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-lg-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-lg-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-lg-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-lg-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-lg-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-lg-center {
+  justify-content:center!important
+ }
+ .justify-content-lg-between {
+  justify-content:space-between!important
+ }
+ .justify-content-lg-around {
+  justify-content:space-around!important
+ }
+ .align-items-lg-start {
+  align-items:flex-start!important
+ }
+ .align-items-lg-end {
+  align-items:flex-end!important
+ }
+ .align-items-lg-center {
+  align-items:center!important
+ }
+ .align-items-lg-baseline {
+  align-items:baseline!important
+ }
+ .align-items-lg-stretch {
+  align-items:stretch!important
+ }
+ .align-content-lg-start {
+  align-content:flex-start!important
+ }
+ .align-content-lg-end {
+  align-content:flex-end!important
+ }
+ .align-content-lg-center {
+  align-content:center!important
+ }
+ .align-content-lg-between {
+  align-content:space-between!important
+ }
+ .align-content-lg-around {
+  align-content:space-around!important
+ }
+ .align-content-lg-stretch {
+  align-content:stretch!important
+ }
+ .align-self-lg-auto {
+  align-self:auto!important
+ }
+ .align-self-lg-start {
+  align-self:flex-start!important
+ }
+ .align-self-lg-end {
+  align-self:flex-end!important
+ }
+ .align-self-lg-center {
+  align-self:center!important
+ }
+ .align-self-lg-baseline {
+  align-self:baseline!important
+ }
+ .align-self-lg-stretch {
+  align-self:stretch!important
+ }
+}
+@media (min-width:1200px) {
+ .flex-xl-row {
+  flex-direction:row!important
+ }
+ .flex-xl-column {
+  flex-direction:column!important
+ }
+ .flex-xl-row-reverse {
+  flex-direction:row-reverse!important
+ }
+ .flex-xl-column-reverse {
+  flex-direction:column-reverse!important
+ }
+ .flex-xl-wrap {
+  flex-wrap:wrap!important
+ }
+ .flex-xl-nowrap {
+  flex-wrap:nowrap!important
+ }
+ .flex-xl-wrap-reverse {
+  flex-wrap:wrap-reverse!important
+ }
+ .flex-xl-fill {
+  flex:1 1 auto!important
+ }
+ .flex-xl-grow-0 {
+  flex-grow:0!important
+ }
+ .flex-xl-grow-1 {
+  flex-grow:1!important
+ }
+ .flex-xl-shrink-0 {
+  flex-shrink:0!important
+ }
+ .flex-xl-shrink-1 {
+  flex-shrink:1!important
+ }
+ .justify-content-xl-start {
+  justify-content:flex-start!important
+ }
+ .justify-content-xl-end {
+  justify-content:flex-end!important
+ }
+ .justify-content-xl-center {
+  justify-content:center!important
+ }
+ .justify-content-xl-between {
+  justify-content:space-between!important
+ }
+ .justify-content-xl-around {
+  justify-content:space-around!important
+ }
+ .align-items-xl-start {
+  align-items:flex-start!important
+ }
+ .align-items-xl-end {
+  align-items:flex-end!important
+ }
+ .align-items-xl-center {
+  align-items:center!important
+ }
+ .align-items-xl-baseline {
+  align-items:baseline!important
+ }
+ .align-items-xl-stretch {
+  align-items:stretch!important
+ }
+ .align-content-xl-start {
+  align-content:flex-start!important
+ }
+ .align-content-xl-end {
+  align-content:flex-end!important
+ }
+ .align-content-xl-center {
+  align-content:center!important
+ }
+ .align-content-xl-between {
+  align-content:space-between!important
+ }
+ .align-content-xl-around {
+  align-content:space-around!important
+ }
+ .align-content-xl-stretch {
+  align-content:stretch!important
+ }
+ .align-self-xl-auto {
+  align-self:auto!important
+ }
+ .align-self-xl-start {
+  align-self:flex-start!important
+ }
+ .align-self-xl-end {
+  align-self:flex-end!important
+ }
+ .align-self-xl-center {
+  align-self:center!important
+ }
+ .align-self-xl-baseline {
+  align-self:baseline!important
+ }
+ .align-self-xl-stretch {
+  align-self:stretch!important
+ }
+}
+.float-left {
+ float:left!important
+}
+.float-right {
+ float:right!important
+}
+.float-none {
+ float:none!important
+}
+@media (min-width:576px) {
+ .float-sm-left {
+  float:left!important
+ }
+ .float-sm-right {
+  float:right!important
+ }
+ .float-sm-none {
+  float:none!important
+ }
+}
+@media (min-width:768px) {
+ .float-md-left {
+  float:left!important
+ }
+ .float-md-right {
+  float:right!important
+ }
+ .float-md-none {
+  float:none!important
+ }
+}
+@media (min-width:992px) {
+ .float-lg-left {
+  float:left!important
+ }
+ .float-lg-right {
+  float:right!important
+ }
+ .float-lg-none {
+  float:none!important
+ }
+}
+@media (min-width:1200px) {
+ .float-xl-left {
+  float:left!important
+ }
+ .float-xl-right {
+  float:right!important
+ }
+ .float-xl-none {
+  float:none!important
+ }
+}
+.user-select-all {
+ user-select:all!important
+}
+.user-select-auto {
+ user-select:auto!important
+}
+.user-select-none {
+ user-select:none!important
+}
+.overflow-auto {
+ overflow:auto!important
+}
+.overflow-hidden {
+ overflow:hidden!important
+}
+.position-static {
+ position:static!important
+}
+.position-relative {
+ position:relative!important
+}
+.position-absolute {
+ position:absolute!important
+}
+.position-fixed {
+ position:fixed!important
+}
+.position-sticky {
+ position:sticky!important
+}
+.fixed-top {
+ position:fixed;
+ top:0;
+ right:0;
+ left:0;
+ z-index:1030
+}
+.fixed-bottom {
+ position:fixed;
+ right:0;
+ bottom:0;
+ left:0;
+ z-index:1030
+}
+@supports (position:sticky) {
+ .sticky-top {
+  position:sticky;
+  top:0;
+  z-index:1020
+ }
+}
+.sr-only {
+ position:absolute;
+ width:1px;
+ height:1px;
+ padding:0;
+ margin:-1px;
+ overflow:hidden;
+ clip:rect(0,0,0,0);
+ white-space:nowrap;
+ border:0
+}
+.sr-only-focusable:active,
+.sr-only-focusable:focus {
+ position:static;
+ width:auto;
+ height:auto;
+ overflow:visible;
+ clip:auto;
+ white-space:normal
+}
+.shadow-sm {
+ box-shadow:0 .125rem .25rem rgba(34,34,34,.075)!important
+}
+.shadow {
+ box-shadow:0 .5rem 1rem rgba(34,34,34,.15)!important
+}
+.shadow-lg {
+ box-shadow:0 1rem 3rem rgba(34,34,34,.175)!important
+}
+.shadow-none {
+ box-shadow:none!important
+}
+.w-25 {
+ width:25%!important
+}
+.w-50 {
+ width:50%!important
+}
+.w-75 {
+ width:75%!important
+}
+.w-100 {
+ width:100%!important
+}
+.w-auto {
+ width:auto!important
+}
+.h-25 {
+ height:25%!important
+}
+.h-50 {
+ height:50%!important
+}
+.h-75 {
+ height:75%!important
+}
+.h-100 {
+ height:100%!important
+}
+.h-auto {
+ height:auto!important
+}
+.mw-100 {
+ max-width:100%!important
+}
+.mh-100 {
+ max-height:100%!important
+}
+.min-vw-100 {
+ min-width:100vw!important
+}
+.min-vh-100 {
+ min-height:100vh!important
+}
+.vw-100 {
+ width:100vw!important
+}
+.vh-100 {
+ height:100vh!important
+}
+.m-0 {
+ margin:0!important
+}
+.mt-0,
+.my-0 {
+ margin-top:0!important
+}
+.mr-0,
+.mx-0 {
+ margin-right:0!important
+}
+.mb-0,
+.my-0 {
+ margin-bottom:0!important
+}
+.ml-0,
+.mx-0 {
+ margin-left:0!important
+}
+.m-1 {
+ margin:.25rem!important
+}
+.mt-1,
+.my-1 {
+ margin-top:.25rem!important
+}
+.mr-1,
+.mx-1 {
+ margin-right:.25rem!important
+}
+.mb-1,
+.my-1 {
+ margin-bottom:.25rem!important
+}
+.ml-1,
+.mx-1 {
+ margin-left:.25rem!important
+}
+.m-2 {
+ margin:.5rem!important
+}
+.mt-2,
+.my-2 {
+ margin-top:.5rem!important
+}
+.mr-2,
+.mx-2 {
+ margin-right:.5rem!important
+}
+.mb-2,
+.my-2 {
+ margin-bottom:.5rem!important
+}
+.ml-2,
+.mx-2 {
+ margin-left:.5rem!important
+}
+.m-3 {
+ margin:1rem!important
+}
+.mt-3,
+.my-3 {
+ margin-top:1rem!important
+}
+.mr-3,
+.mx-3 {
+ margin-right:1rem!important
+}
+.mb-3,
+.my-3 {
+ margin-bottom:1rem!important
+}
+.ml-3,
+.mx-3 {
+ margin-left:1rem!important
+}
+.m-4 {
+ margin:1.5rem!important
+}
+.mt-4,
+.my-4 {
+ margin-top:1.5rem!important
+}
+.mr-4,
+.mx-4 {
+ margin-right:1.5rem!important
+}
+.mb-4,
+.my-4 {
+ margin-bottom:1.5rem!important
+}
+.ml-4,
+.mx-4 {
+ margin-left:1.5rem!important
+}
+.m-5 {
+ margin:3rem!important
+}
+.mt-5,
+.my-5 {
+ margin-top:3rem!important
+}
+.mr-5,
+.mx-5 {
+ margin-right:3rem!important
+}
+.mb-5,
+.my-5 {
+ margin-bottom:3rem!important
+}
+.ml-5,
+.mx-5 {
+ margin-left:3rem!important
+}
+.p-0 {
+ padding:0!important
+}
+.pt-0,
+.py-0 {
+ padding-top:0!important
+}
+.pr-0,
+.px-0 {
+ padding-right:0!important
+}
+.pb-0,
+.py-0 {
+ padding-bottom:0!important
+}
+.pl-0,
+.px-0 {
+ padding-left:0!important
+}
+.p-1 {
+ padding:.25rem!important
+}
+.pt-1,
+.py-1 {
+ padding-top:.25rem!important
+}
+.pr-1,
+.px-1 {
+ padding-right:.25rem!important
+}
+.pb-1,
+.py-1 {
+ padding-bottom:.25rem!important
+}
+.pl-1,
+.px-1 {
+ padding-left:.25rem!important
+}
+.p-2 {
+ padding:.5rem!important
+}
+.pt-2,
+.py-2 {
+ padding-top:.5rem!important
+}
+.pr-2,
+.px-2 {
+ padding-right:.5rem!important
+}
+.pb-2,
+.py-2 {
+ padding-bottom:.5rem!important
+}
+.pl-2,
+.px-2 {
+ padding-left:.5rem!important
+}
+.p-3 {
+ padding:1rem!important
+}
+.pt-3,
+.py-3 {
+ padding-top:1rem!important
+}
+.pr-3,
+.px-3 {
+ padding-right:1rem!important
+}
+.pb-3,
+.py-3 {
+ padding-bottom:1rem!important
+}
+.pl-3,
+.px-3 {
+ padding-left:1rem!important
+}
+.p-4 {
+ padding:1.5rem!important
+}
+.pt-4,
+.py-4 {
+ padding-top:1.5rem!important
+}
+.pr-4,
+.px-4 {
+ padding-right:1.5rem!important
+}
+.pb-4,
+.py-4 {
+ padding-bottom:1.5rem!important
+}
+.pl-4,
+.px-4 {
+ padding-left:1.5rem!important
+}
+.p-5 {
+ padding:3rem!important
+}
+.pt-5,
+.py-5 {
+ padding-top:3rem!important
+}
+.pr-5,
+.px-5 {
+ padding-right:3rem!important
+}
+.pb-5,
+.py-5 {
+ padding-bottom:3rem!important
+}
+.pl-5,
+.px-5 {
+ padding-left:3rem!important
+}
+.m-n1 {
+ margin:-.25rem!important
+}
+.mt-n1,
+.my-n1 {
+ margin-top:-.25rem!important
+}
+.mr-n1,
+.mx-n1 {
+ margin-right:-.25rem!important
+}
+.mb-n1,
+.my-n1 {
+ margin-bottom:-.25rem!important
+}
+.ml-n1,
+.mx-n1 {
+ margin-left:-.25rem!important
+}
+.m-n2 {
+ margin:-.5rem!important
+}
+.mt-n2,
+.my-n2 {
+ margin-top:-.5rem!important
+}
+.mr-n2,
+.mx-n2 {
+ margin-right:-.5rem!important
+}
+.mb-n2,
+.my-n2 {
+ margin-bottom:-.5rem!important
+}
+.ml-n2,
+.mx-n2 {
+ margin-left:-.5rem!important
+}
+.m-n3 {
+ margin:-1rem!important
+}
+.mt-n3,
+.my-n3 {
+ margin-top:-1rem!important
+}
+.mr-n3,
+.mx-n3 {
+ margin-right:-1rem!important
+}
+.mb-n3,
+.my-n3 {
+ margin-bottom:-1rem!important
+}
+.ml-n3,
+.mx-n3 {
+ margin-left:-1rem!important
+}
+.m-n4 {
+ margin:-1.5rem!important
+}
+.mt-n4,
+.my-n4 {
+ margin-top:-1.5rem!important
+}
+.mr-n4,
+.mx-n4 {
+ margin-right:-1.5rem!important
+}
+.mb-n4,
+.my-n4 {
+ margin-bottom:-1.5rem!important
+}
+.ml-n4,
+.mx-n4 {
+ margin-left:-1.5rem!important
+}
+.m-n5 {
+ margin:-3rem!important
+}
+.mt-n5,
+.my-n5 {
+ margin-top:-3rem!important
+}
+.mr-n5,
+.mx-n5 {
+ margin-right:-3rem!important
+}
+.mb-n5,
+.my-n5 {
+ margin-bottom:-3rem!important
+}
+.ml-n5,
+.mx-n5 {
+ margin-left:-3rem!important
+}
+.m-auto {
+ margin:auto!important
+}
+.mt-auto,
+.my-auto {
+ margin-top:auto!important
+}
+.mr-auto,
+.mx-auto {
+ margin-right:auto!important
+}
+.mb-auto,
+.my-auto {
+ margin-bottom:auto!important
+}
+.ml-auto,
+.mx-auto {
+ margin-left:auto!important
+}
+@media (min-width:576px) {
+ .m-sm-0 {
+  margin:0!important
+ }
+ .mt-sm-0,
+ .my-sm-0 {
+  margin-top:0!important
+ }
+ .mr-sm-0,
+ .mx-sm-0 {
+  margin-right:0!important
+ }
+ .mb-sm-0,
+ .my-sm-0 {
+  margin-bottom:0!important
+ }
+ .ml-sm-0,
+ .mx-sm-0 {
+  margin-left:0!important
+ }
+ .m-sm-1 {
+  margin:.25rem!important
+ }
+ .mt-sm-1,
+ .my-sm-1 {
+  margin-top:.25rem!important
+ }
+ .mr-sm-1,
+ .mx-sm-1 {
+  margin-right:.25rem!important
+ }
+ .mb-sm-1,
+ .my-sm-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-sm-1,
+ .mx-sm-1 {
+  margin-left:.25rem!important
+ }
+ .m-sm-2 {
+  margin:.5rem!important
+ }
+ .mt-sm-2,
+ .my-sm-2 {
+  margin-top:.5rem!important
+ }
+ .mr-sm-2,
+ .mx-sm-2 {
+  margin-right:.5rem!important
+ }
+ .mb-sm-2,
+ .my-sm-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-sm-2,
+ .mx-sm-2 {
+  margin-left:.5rem!important
+ }
+ .m-sm-3 {
+  margin:1rem!important
+ }
+ .mt-sm-3,
+ .my-sm-3 {
+  margin-top:1rem!important
+ }
+ .mr-sm-3,
+ .mx-sm-3 {
+  margin-right:1rem!important
+ }
+ .mb-sm-3,
+ .my-sm-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-sm-3,
+ .mx-sm-3 {
+  margin-left:1rem!important
+ }
+ .m-sm-4 {
+  margin:1.5rem!important
+ }
+ .mt-sm-4,
+ .my-sm-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-sm-4,
+ .mx-sm-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-sm-4,
+ .my-sm-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-sm-4,
+ .mx-sm-4 {
+  margin-left:1.5rem!important
+ }
+ .m-sm-5 {
+  margin:3rem!important
+ }
+ .mt-sm-5,
+ .my-sm-5 {
+  margin-top:3rem!important
+ }
+ .mr-sm-5,
+ .mx-sm-5 {
+  margin-right:3rem!important
+ }
+ .mb-sm-5,
+ .my-sm-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-sm-5,
+ .mx-sm-5 {
+  margin-left:3rem!important
+ }
+ .p-sm-0 {
+  padding:0!important
+ }
+ .pt-sm-0,
+ .py-sm-0 {
+  padding-top:0!important
+ }
+ .pr-sm-0,
+ .px-sm-0 {
+  padding-right:0!important
+ }
+ .pb-sm-0,
+ .py-sm-0 {
+  padding-bottom:0!important
+ }
+ .pl-sm-0,
+ .px-sm-0 {
+  padding-left:0!important
+ }
+ .p-sm-1 {
+  padding:.25rem!important
+ }
+ .pt-sm-1,
+ .py-sm-1 {
+  padding-top:.25rem!important
+ }
+ .pr-sm-1,
+ .px-sm-1 {
+  padding-right:.25rem!important
+ }
+ .pb-sm-1,
+ .py-sm-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-sm-1,
+ .px-sm-1 {
+  padding-left:.25rem!important
+ }
+ .p-sm-2 {
+  padding:.5rem!important
+ }
+ .pt-sm-2,
+ .py-sm-2 {
+  padding-top:.5rem!important
+ }
+ .pr-sm-2,
+ .px-sm-2 {
+  padding-right:.5rem!important
+ }
+ .pb-sm-2,
+ .py-sm-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-sm-2,
+ .px-sm-2 {
+  padding-left:.5rem!important
+ }
+ .p-sm-3 {
+  padding:1rem!important
+ }
+ .pt-sm-3,
+ .py-sm-3 {
+  padding-top:1rem!important
+ }
+ .pr-sm-3,
+ .px-sm-3 {
+  padding-right:1rem!important
+ }
+ .pb-sm-3,
+ .py-sm-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-sm-3,
+ .px-sm-3 {
+  padding-left:1rem!important
+ }
+ .p-sm-4 {
+  padding:1.5rem!important
+ }
+ .pt-sm-4,
+ .py-sm-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-sm-4,
+ .px-sm-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-sm-4,
+ .py-sm-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-sm-4,
+ .px-sm-4 {
+  padding-left:1.5rem!important
+ }
+ .p-sm-5 {
+  padding:3rem!important
+ }
+ .pt-sm-5,
+ .py-sm-5 {
+  padding-top:3rem!important
+ }
+ .pr-sm-5,
+ .px-sm-5 {
+  padding-right:3rem!important
+ }
+ .pb-sm-5,
+ .py-sm-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-sm-5,
+ .px-sm-5 {
+  padding-left:3rem!important
+ }
+ .m-sm-n1 {
+  margin:-.25rem!important
+ }
+ .mt-sm-n1,
+ .my-sm-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-sm-n1,
+ .mx-sm-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-sm-n1,
+ .my-sm-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-sm-n1,
+ .mx-sm-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-sm-n2 {
+  margin:-.5rem!important
+ }
+ .mt-sm-n2,
+ .my-sm-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-sm-n2,
+ .mx-sm-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-sm-n2,
+ .my-sm-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-sm-n2,
+ .mx-sm-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-sm-n3 {
+  margin:-1rem!important
+ }
+ .mt-sm-n3,
+ .my-sm-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-sm-n3,
+ .mx-sm-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-sm-n3,
+ .my-sm-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-sm-n3,
+ .mx-sm-n3 {
+  margin-left:-1rem!important
+ }
+ .m-sm-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-sm-n4,
+ .my-sm-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-sm-n4,
+ .mx-sm-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-sm-n4,
+ .my-sm-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-sm-n4,
+ .mx-sm-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-sm-n5 {
+  margin:-3rem!important
+ }
+ .mt-sm-n5,
+ .my-sm-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-sm-n5,
+ .mx-sm-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-sm-n5,
+ .my-sm-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-sm-n5,
+ .mx-sm-n5 {
+  margin-left:-3rem!important
+ }
+ .m-sm-auto {
+  margin:auto!important
+ }
+ .mt-sm-auto,
+ .my-sm-auto {
+  margin-top:auto!important
+ }
+ .mr-sm-auto,
+ .mx-sm-auto {
+  margin-right:auto!important
+ }
+ .mb-sm-auto,
+ .my-sm-auto {
+  margin-bottom:auto!important
+ }
+ .ml-sm-auto,
+ .mx-sm-auto {
+  margin-left:auto!important
+ }
+}
+@media (min-width:768px) {
+ .m-md-0 {
+  margin:0!important
+ }
+ .mt-md-0,
+ .my-md-0 {
+  margin-top:0!important
+ }
+ .mr-md-0,
+ .mx-md-0 {
+  margin-right:0!important
+ }
+ .mb-md-0,
+ .my-md-0 {
+  margin-bottom:0!important
+ }
+ .ml-md-0,
+ .mx-md-0 {
+  margin-left:0!important
+ }
+ .m-md-1 {
+  margin:.25rem!important
+ }
+ .mt-md-1,
+ .my-md-1 {
+  margin-top:.25rem!important
+ }
+ .mr-md-1,
+ .mx-md-1 {
+  margin-right:.25rem!important
+ }
+ .mb-md-1,
+ .my-md-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-md-1,
+ .mx-md-1 {
+  margin-left:.25rem!important
+ }
+ .m-md-2 {
+  margin:.5rem!important
+ }
+ .mt-md-2,
+ .my-md-2 {
+  margin-top:.5rem!important
+ }
+ .mr-md-2,
+ .mx-md-2 {
+  margin-right:.5rem!important
+ }
+ .mb-md-2,
+ .my-md-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-md-2,
+ .mx-md-2 {
+  margin-left:.5rem!important
+ }
+ .m-md-3 {
+  margin:1rem!important
+ }
+ .mt-md-3,
+ .my-md-3 {
+  margin-top:1rem!important
+ }
+ .mr-md-3,
+ .mx-md-3 {
+  margin-right:1rem!important
+ }
+ .mb-md-3,
+ .my-md-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-md-3,
+ .mx-md-3 {
+  margin-left:1rem!important
+ }
+ .m-md-4 {
+  margin:1.5rem!important
+ }
+ .mt-md-4,
+ .my-md-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-md-4,
+ .mx-md-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-md-4,
+ .my-md-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-md-4,
+ .mx-md-4 {
+  margin-left:1.5rem!important
+ }
+ .m-md-5 {
+  margin:3rem!important
+ }
+ .mt-md-5,
+ .my-md-5 {
+  margin-top:3rem!important
+ }
+ .mr-md-5,
+ .mx-md-5 {
+  margin-right:3rem!important
+ }
+ .mb-md-5,
+ .my-md-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-md-5,
+ .mx-md-5 {
+  margin-left:3rem!important
+ }
+ .p-md-0 {
+  padding:0!important
+ }
+ .pt-md-0,
+ .py-md-0 {
+  padding-top:0!important
+ }
+ .pr-md-0,
+ .px-md-0 {
+  padding-right:0!important
+ }
+ .pb-md-0,
+ .py-md-0 {
+  padding-bottom:0!important
+ }
+ .pl-md-0,
+ .px-md-0 {
+  padding-left:0!important
+ }
+ .p-md-1 {
+  padding:.25rem!important
+ }
+ .pt-md-1,
+ .py-md-1 {
+  padding-top:.25rem!important
+ }
+ .pr-md-1,
+ .px-md-1 {
+  padding-right:.25rem!important
+ }
+ .pb-md-1,
+ .py-md-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-md-1,
+ .px-md-1 {
+  padding-left:.25rem!important
+ }
+ .p-md-2 {
+  padding:.5rem!important
+ }
+ .pt-md-2,
+ .py-md-2 {
+  padding-top:.5rem!important
+ }
+ .pr-md-2,
+ .px-md-2 {
+  padding-right:.5rem!important
+ }
+ .pb-md-2,
+ .py-md-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-md-2,
+ .px-md-2 {
+  padding-left:.5rem!important
+ }
+ .p-md-3 {
+  padding:1rem!important
+ }
+ .pt-md-3,
+ .py-md-3 {
+  padding-top:1rem!important
+ }
+ .pr-md-3,
+ .px-md-3 {
+  padding-right:1rem!important
+ }
+ .pb-md-3,
+ .py-md-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-md-3,
+ .px-md-3 {
+  padding-left:1rem!important
+ }
+ .p-md-4 {
+  padding:1.5rem!important
+ }
+ .pt-md-4,
+ .py-md-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-md-4,
+ .px-md-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-md-4,
+ .py-md-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-md-4,
+ .px-md-4 {
+  padding-left:1.5rem!important
+ }
+ .p-md-5 {
+  padding:3rem!important
+ }
+ .pt-md-5,
+ .py-md-5 {
+  padding-top:3rem!important
+ }
+ .pr-md-5,
+ .px-md-5 {
+  padding-right:3rem!important
+ }
+ .pb-md-5,
+ .py-md-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-md-5,
+ .px-md-5 {
+  padding-left:3rem!important
+ }
+ .m-md-n1 {
+  margin:-.25rem!important
+ }
+ .mt-md-n1,
+ .my-md-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-md-n1,
+ .mx-md-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-md-n1,
+ .my-md-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-md-n1,
+ .mx-md-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-md-n2 {
+  margin:-.5rem!important
+ }
+ .mt-md-n2,
+ .my-md-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-md-n2,
+ .mx-md-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-md-n2,
+ .my-md-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-md-n2,
+ .mx-md-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-md-n3 {
+  margin:-1rem!important
+ }
+ .mt-md-n3,
+ .my-md-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-md-n3,
+ .mx-md-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-md-n3,
+ .my-md-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-md-n3,
+ .mx-md-n3 {
+  margin-left:-1rem!important
+ }
+ .m-md-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-md-n4,
+ .my-md-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-md-n4,
+ .mx-md-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-md-n4,
+ .my-md-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-md-n4,
+ .mx-md-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-md-n5 {
+  margin:-3rem!important
+ }
+ .mt-md-n5,
+ .my-md-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-md-n5,
+ .mx-md-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-md-n5,
+ .my-md-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-md-n5,
+ .mx-md-n5 {
+  margin-left:-3rem!important
+ }
+ .m-md-auto {
+  margin:auto!important
+ }
+ .mt-md-auto,
+ .my-md-auto {
+  margin-top:auto!important
+ }
+ .mr-md-auto,
+ .mx-md-auto {
+  margin-right:auto!important
+ }
+ .mb-md-auto,
+ .my-md-auto {
+  margin-bottom:auto!important
+ }
+ .ml-md-auto,
+ .mx-md-auto {
+  margin-left:auto!important
+ }
+}
+@media (min-width:992px) {
+ .m-lg-0 {
+  margin:0!important
+ }
+ .mt-lg-0,
+ .my-lg-0 {
+  margin-top:0!important
+ }
+ .mr-lg-0,
+ .mx-lg-0 {
+  margin-right:0!important
+ }
+ .mb-lg-0,
+ .my-lg-0 {
+  margin-bottom:0!important
+ }
+ .ml-lg-0,
+ .mx-lg-0 {
+  margin-left:0!important
+ }
+ .m-lg-1 {
+  margin:.25rem!important
+ }
+ .mt-lg-1,
+ .my-lg-1 {
+  margin-top:.25rem!important
+ }
+ .mr-lg-1,
+ .mx-lg-1 {
+  margin-right:.25rem!important
+ }
+ .mb-lg-1,
+ .my-lg-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-lg-1,
+ .mx-lg-1 {
+  margin-left:.25rem!important
+ }
+ .m-lg-2 {
+  margin:.5rem!important
+ }
+ .mt-lg-2,
+ .my-lg-2 {
+  margin-top:.5rem!important
+ }
+ .mr-lg-2,
+ .mx-lg-2 {
+  margin-right:.5rem!important
+ }
+ .mb-lg-2,
+ .my-lg-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-lg-2,
+ .mx-lg-2 {
+  margin-left:.5rem!important
+ }
+ .m-lg-3 {
+  margin:1rem!important
+ }
+ .mt-lg-3,
+ .my-lg-3 {
+  margin-top:1rem!important
+ }
+ .mr-lg-3,
+ .mx-lg-3 {
+  margin-right:1rem!important
+ }
+ .mb-lg-3,
+ .my-lg-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-lg-3,
+ .mx-lg-3 {
+  margin-left:1rem!important
+ }
+ .m-lg-4 {
+  margin:1.5rem!important
+ }
+ .mt-lg-4,
+ .my-lg-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-lg-4,
+ .mx-lg-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-lg-4,
+ .my-lg-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-lg-4,
+ .mx-lg-4 {
+  margin-left:1.5rem!important
+ }
+ .m-lg-5 {
+  margin:3rem!important
+ }
+ .mt-lg-5,
+ .my-lg-5 {
+  margin-top:3rem!important
+ }
+ .mr-lg-5,
+ .mx-lg-5 {
+  margin-right:3rem!important
+ }
+ .mb-lg-5,
+ .my-lg-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-lg-5,
+ .mx-lg-5 {
+  margin-left:3rem!important
+ }
+ .p-lg-0 {
+  padding:0!important
+ }
+ .pt-lg-0,
+ .py-lg-0 {
+  padding-top:0!important
+ }
+ .pr-lg-0,
+ .px-lg-0 {
+  padding-right:0!important
+ }
+ .pb-lg-0,
+ .py-lg-0 {
+  padding-bottom:0!important
+ }
+ .pl-lg-0,
+ .px-lg-0 {
+  padding-left:0!important
+ }
+ .p-lg-1 {
+  padding:.25rem!important
+ }
+ .pt-lg-1,
+ .py-lg-1 {
+  padding-top:.25rem!important
+ }
+ .pr-lg-1,
+ .px-lg-1 {
+  padding-right:.25rem!important
+ }
+ .pb-lg-1,
+ .py-lg-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-lg-1,
+ .px-lg-1 {
+  padding-left:.25rem!important
+ }
+ .p-lg-2 {
+  padding:.5rem!important
+ }
+ .pt-lg-2,
+ .py-lg-2 {
+  padding-top:.5rem!important
+ }
+ .pr-lg-2,
+ .px-lg-2 {
+  padding-right:.5rem!important
+ }
+ .pb-lg-2,
+ .py-lg-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-lg-2,
+ .px-lg-2 {
+  padding-left:.5rem!important
+ }
+ .p-lg-3 {
+  padding:1rem!important
+ }
+ .pt-lg-3,
+ .py-lg-3 {
+  padding-top:1rem!important
+ }
+ .pr-lg-3,
+ .px-lg-3 {
+  padding-right:1rem!important
+ }
+ .pb-lg-3,
+ .py-lg-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-lg-3,
+ .px-lg-3 {
+  padding-left:1rem!important
+ }
+ .p-lg-4 {
+  padding:1.5rem!important
+ }
+ .pt-lg-4,
+ .py-lg-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-lg-4,
+ .px-lg-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-lg-4,
+ .py-lg-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-lg-4,
+ .px-lg-4 {
+  padding-left:1.5rem!important
+ }
+ .p-lg-5 {
+  padding:3rem!important
+ }
+ .pt-lg-5,
+ .py-lg-5 {
+  padding-top:3rem!important
+ }
+ .pr-lg-5,
+ .px-lg-5 {
+  padding-right:3rem!important
+ }
+ .pb-lg-5,
+ .py-lg-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-lg-5,
+ .px-lg-5 {
+  padding-left:3rem!important
+ }
+ .m-lg-n1 {
+  margin:-.25rem!important
+ }
+ .mt-lg-n1,
+ .my-lg-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-lg-n1,
+ .mx-lg-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-lg-n1,
+ .my-lg-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-lg-n1,
+ .mx-lg-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-lg-n2 {
+  margin:-.5rem!important
+ }
+ .mt-lg-n2,
+ .my-lg-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-lg-n2,
+ .mx-lg-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-lg-n2,
+ .my-lg-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-lg-n2,
+ .mx-lg-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-lg-n3 {
+  margin:-1rem!important
+ }
+ .mt-lg-n3,
+ .my-lg-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-lg-n3,
+ .mx-lg-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-lg-n3,
+ .my-lg-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-lg-n3,
+ .mx-lg-n3 {
+  margin-left:-1rem!important
+ }
+ .m-lg-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-lg-n4,
+ .my-lg-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-lg-n4,
+ .mx-lg-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-lg-n4,
+ .my-lg-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-lg-n4,
+ .mx-lg-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-lg-n5 {
+  margin:-3rem!important
+ }
+ .mt-lg-n5,
+ .my-lg-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-lg-n5,
+ .mx-lg-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-lg-n5,
+ .my-lg-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-lg-n5,
+ .mx-lg-n5 {
+  margin-left:-3rem!important
+ }
+ .m-lg-auto {
+  margin:auto!important
+ }
+ .mt-lg-auto,
+ .my-lg-auto {
+  margin-top:auto!important
+ }
+ .mr-lg-auto,
+ .mx-lg-auto {
+  margin-right:auto!important
+ }
+ .mb-lg-auto,
+ .my-lg-auto {
+  margin-bottom:auto!important
+ }
+ .ml-lg-auto,
+ .mx-lg-auto {
+  margin-left:auto!important
+ }
+}
+@media (min-width:1200px) {
+ .m-xl-0 {
+  margin:0!important
+ }
+ .mt-xl-0,
+ .my-xl-0 {
+  margin-top:0!important
+ }
+ .mr-xl-0,
+ .mx-xl-0 {
+  margin-right:0!important
+ }
+ .mb-xl-0,
+ .my-xl-0 {
+  margin-bottom:0!important
+ }
+ .ml-xl-0,
+ .mx-xl-0 {
+  margin-left:0!important
+ }
+ .m-xl-1 {
+  margin:.25rem!important
+ }
+ .mt-xl-1,
+ .my-xl-1 {
+  margin-top:.25rem!important
+ }
+ .mr-xl-1,
+ .mx-xl-1 {
+  margin-right:.25rem!important
+ }
+ .mb-xl-1,
+ .my-xl-1 {
+  margin-bottom:.25rem!important
+ }
+ .ml-xl-1,
+ .mx-xl-1 {
+  margin-left:.25rem!important
+ }
+ .m-xl-2 {
+  margin:.5rem!important
+ }
+ .mt-xl-2,
+ .my-xl-2 {
+  margin-top:.5rem!important
+ }
+ .mr-xl-2,
+ .mx-xl-2 {
+  margin-right:.5rem!important
+ }
+ .mb-xl-2,
+ .my-xl-2 {
+  margin-bottom:.5rem!important
+ }
+ .ml-xl-2,
+ .mx-xl-2 {
+  margin-left:.5rem!important
+ }
+ .m-xl-3 {
+  margin:1rem!important
+ }
+ .mt-xl-3,
+ .my-xl-3 {
+  margin-top:1rem!important
+ }
+ .mr-xl-3,
+ .mx-xl-3 {
+  margin-right:1rem!important
+ }
+ .mb-xl-3,
+ .my-xl-3 {
+  margin-bottom:1rem!important
+ }
+ .ml-xl-3,
+ .mx-xl-3 {
+  margin-left:1rem!important
+ }
+ .m-xl-4 {
+  margin:1.5rem!important
+ }
+ .mt-xl-4,
+ .my-xl-4 {
+  margin-top:1.5rem!important
+ }
+ .mr-xl-4,
+ .mx-xl-4 {
+  margin-right:1.5rem!important
+ }
+ .mb-xl-4,
+ .my-xl-4 {
+  margin-bottom:1.5rem!important
+ }
+ .ml-xl-4,
+ .mx-xl-4 {
+  margin-left:1.5rem!important
+ }
+ .m-xl-5 {
+  margin:3rem!important
+ }
+ .mt-xl-5,
+ .my-xl-5 {
+  margin-top:3rem!important
+ }
+ .mr-xl-5,
+ .mx-xl-5 {
+  margin-right:3rem!important
+ }
+ .mb-xl-5,
+ .my-xl-5 {
+  margin-bottom:3rem!important
+ }
+ .ml-xl-5,
+ .mx-xl-5 {
+  margin-left:3rem!important
+ }
+ .p-xl-0 {
+  padding:0!important
+ }
+ .pt-xl-0,
+ .py-xl-0 {
+  padding-top:0!important
+ }
+ .pr-xl-0,
+ .px-xl-0 {
+  padding-right:0!important
+ }
+ .pb-xl-0,
+ .py-xl-0 {
+  padding-bottom:0!important
+ }
+ .pl-xl-0,
+ .px-xl-0 {
+  padding-left:0!important
+ }
+ .p-xl-1 {
+  padding:.25rem!important
+ }
+ .pt-xl-1,
+ .py-xl-1 {
+  padding-top:.25rem!important
+ }
+ .pr-xl-1,
+ .px-xl-1 {
+  padding-right:.25rem!important
+ }
+ .pb-xl-1,
+ .py-xl-1 {
+  padding-bottom:.25rem!important
+ }
+ .pl-xl-1,
+ .px-xl-1 {
+  padding-left:.25rem!important
+ }
+ .p-xl-2 {
+  padding:.5rem!important
+ }
+ .pt-xl-2,
+ .py-xl-2 {
+  padding-top:.5rem!important
+ }
+ .pr-xl-2,
+ .px-xl-2 {
+  padding-right:.5rem!important
+ }
+ .pb-xl-2,
+ .py-xl-2 {
+  padding-bottom:.5rem!important
+ }
+ .pl-xl-2,
+ .px-xl-2 {
+  padding-left:.5rem!important
+ }
+ .p-xl-3 {
+  padding:1rem!important
+ }
+ .pt-xl-3,
+ .py-xl-3 {
+  padding-top:1rem!important
+ }
+ .pr-xl-3,
+ .px-xl-3 {
+  padding-right:1rem!important
+ }
+ .pb-xl-3,
+ .py-xl-3 {
+  padding-bottom:1rem!important
+ }
+ .pl-xl-3,
+ .px-xl-3 {
+  padding-left:1rem!important
+ }
+ .p-xl-4 {
+  padding:1.5rem!important
+ }
+ .pt-xl-4,
+ .py-xl-4 {
+  padding-top:1.5rem!important
+ }
+ .pr-xl-4,
+ .px-xl-4 {
+  padding-right:1.5rem!important
+ }
+ .pb-xl-4,
+ .py-xl-4 {
+  padding-bottom:1.5rem!important
+ }
+ .pl-xl-4,
+ .px-xl-4 {
+  padding-left:1.5rem!important
+ }
+ .p-xl-5 {
+  padding:3rem!important
+ }
+ .pt-xl-5,
+ .py-xl-5 {
+  padding-top:3rem!important
+ }
+ .pr-xl-5,
+ .px-xl-5 {
+  padding-right:3rem!important
+ }
+ .pb-xl-5,
+ .py-xl-5 {
+  padding-bottom:3rem!important
+ }
+ .pl-xl-5,
+ .px-xl-5 {
+  padding-left:3rem!important
+ }
+ .m-xl-n1 {
+  margin:-.25rem!important
+ }
+ .mt-xl-n1,
+ .my-xl-n1 {
+  margin-top:-.25rem!important
+ }
+ .mr-xl-n1,
+ .mx-xl-n1 {
+  margin-right:-.25rem!important
+ }
+ .mb-xl-n1,
+ .my-xl-n1 {
+  margin-bottom:-.25rem!important
+ }
+ .ml-xl-n1,
+ .mx-xl-n1 {
+  margin-left:-.25rem!important
+ }
+ .m-xl-n2 {
+  margin:-.5rem!important
+ }
+ .mt-xl-n2,
+ .my-xl-n2 {
+  margin-top:-.5rem!important
+ }
+ .mr-xl-n2,
+ .mx-xl-n2 {
+  margin-right:-.5rem!important
+ }
+ .mb-xl-n2,
+ .my-xl-n2 {
+  margin-bottom:-.5rem!important
+ }
+ .ml-xl-n2,
+ .mx-xl-n2 {
+  margin-left:-.5rem!important
+ }
+ .m-xl-n3 {
+  margin:-1rem!important
+ }
+ .mt-xl-n3,
+ .my-xl-n3 {
+  margin-top:-1rem!important
+ }
+ .mr-xl-n3,
+ .mx-xl-n3 {
+  margin-right:-1rem!important
+ }
+ .mb-xl-n3,
+ .my-xl-n3 {
+  margin-bottom:-1rem!important
+ }
+ .ml-xl-n3,
+ .mx-xl-n3 {
+  margin-left:-1rem!important
+ }
+ .m-xl-n4 {
+  margin:-1.5rem!important
+ }
+ .mt-xl-n4,
+ .my-xl-n4 {
+  margin-top:-1.5rem!important
+ }
+ .mr-xl-n4,
+ .mx-xl-n4 {
+  margin-right:-1.5rem!important
+ }
+ .mb-xl-n4,
+ .my-xl-n4 {
+  margin-bottom:-1.5rem!important
+ }
+ .ml-xl-n4,
+ .mx-xl-n4 {
+  margin-left:-1.5rem!important
+ }
+ .m-xl-n5 {
+  margin:-3rem!important
+ }
+ .mt-xl-n5,
+ .my-xl-n5 {
+  margin-top:-3rem!important
+ }
+ .mr-xl-n5,
+ .mx-xl-n5 {
+  margin-right:-3rem!important
+ }
+ .mb-xl-n5,
+ .my-xl-n5 {
+  margin-bottom:-3rem!important
+ }
+ .ml-xl-n5,
+ .mx-xl-n5 {
+  margin-left:-3rem!important
+ }
+ .m-xl-auto {
+  margin:auto!important
+ }
+ .mt-xl-auto,
+ .my-xl-auto {
+  margin-top:auto!important
+ }
+ .mr-xl-auto,
+ .mx-xl-auto {
+  margin-right:auto!important
+ }
+ .mb-xl-auto,
+ .my-xl-auto {
+  margin-bottom:auto!important
+ }
+ .ml-xl-auto,
+ .mx-xl-auto {
+  margin-left:auto!important
+ }
+}
+.stretched-link::after {
+ position:absolute;
+ top:0;
+ right:0;
+ bottom:0;
+ left:0;
+ z-index:1;
+ pointer-events:auto;
+ content:"";
+ background-color:rgba(0,0,0,0)
+}
+.text-monospace {
+ font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important
+}
+.text-justify {
+ text-align:justify!important
+}
+.text-wrap {
+ white-space:normal!important
+}
+.text-nowrap {
+ white-space:nowrap!important
+}
+.text-truncate {
+ overflow:hidden;
+ text-overflow:ellipsis;
+ white-space:nowrap
+}
+.text-left {
+ text-align:left!important
+}
+.text-right {
+ text-align:right!important
+}
+.text-center {
+ text-align:center!important
+}
+@media (min-width:576px) {
+ .text-sm-left {
+  text-align:left!important
+ }
+ .text-sm-right {
+  text-align:right!important
+ }
+ .text-sm-center {
+  text-align:center!important
+ }
+}
+@media (min-width:768px) {
+ .text-md-left {
+  text-align:left!important
+ }
+ .text-md-right {
+  text-align:right!important
+ }
+ .text-md-center {
+  text-align:center!important
+ }
+}
+@media (min-width:992px) {
+ .text-lg-left {
+  text-align:left!important
+ }
+ .text-lg-right {
+  text-align:right!important
+ }
+ .text-lg-center {
+  text-align:center!important
+ }
+}
+@media (min-width:1200px) {
+ .text-xl-left {
+  text-align:left!important
+ }
+ .text-xl-right {
+  text-align:right!important
+ }
+ .text-xl-center {
+  text-align:center!important
+ }
+}
+.text-lowercase {
+ text-transform:lowercase!important
+}
+.text-uppercase {
+ text-transform:uppercase!important
+}
+.text-capitalize {
+ text-transform:capitalize!important
+}
+.font-weight-light {
+ font-weight:300!important
+}
+.font-weight-lighter {
+ font-weight:lighter!important
+}
+.font-weight-normal {
+ font-weight:400!important
+}
+.font-weight-bold {
+ font-weight:600!important
+}
+.font-weight-bolder {
+ font-weight:bolder!important
+}
+.font-italic {
+ font-style:italic!important
+}
+.text-white {
+ color:#fff!important
+}
+.text-primary {
+ color:#f1641e!important
+}
+a.text-primary:focus,
+a.text-primary:hover {
+ color:#b7440b!important
+}
+.text-secondary {
+ color:#00c853!important
+}
+a.text-secondary:focus,
+a.text-secondary:hover {
+ color:#007c33!important
+}
+.text-success {
+ color:#6610f2!important
+}
+a.text-success:focus,
+a.text-success:hover {
+ color:#4709ac!important
+}
+.text-info {
+ color:#007bff!important
+}
+a.text-info:focus,
+a.text-info:hover {
+ color:#0056b3!important
+}
+.text-warning {
+ color:#ffc107!important
+}
+a.text-warning:focus,
+a.text-warning:hover {
+ color:#ba8b00!important
+}
+.text-danger {
+ color:#873208!important
+}
+a.text-danger:focus,
+a.text-danger:hover {
+ color:#3f1804!important
+}
+.text-light {
+ color:#f8f9fa!important
+}
+a.text-light:focus,
+a.text-light:hover {
+ color:#cbd3da!important
+}
+.text-dark {
+ color:#343a40!important
+}
+a.text-dark:focus,
+a.text-dark:hover {
+ color:#121416!important
+}
+.text-body {
+ color:#495057!important
+}
+.text-muted {
+ color:#6c757d!important
+}
+.text-black-50 {
+ color:rgba(34,34,34,.5)!important
+}
+.text-white-50 {
+ color:rgba(255,255,255,.5)!important
+}
+.text-hide {
+ font:0/0 a;
+ color:transparent;
+ text-shadow:none;
+ background-color:transparent;
+ border:0
+}
+.text-decoration-none {
+ text-decoration:none!important
+}
+.text-break {
+ word-wrap:break-word!important
+}
+.text-reset {
+ color:inherit!important
+}
+.visible {
+ visibility:visible!important
+}
+.invisible {
+ visibility:hidden!important
+}
+@media print {
+ *,
+ ::after,
+ ::before {
+  text-shadow:none!important;
+  box-shadow:none!important
+ }
+ a:not(.btn) {
+  text-decoration:underline
+ }
+ abbr[title]::after {
+  content:" (" attr(title) ")"
+ }
+ pre {
+  white-space:pre-wrap!important
+ }
+ blockquote,
+ pre {
+  border:1px solid #adb5bd;
+  page-break-inside:avoid
+ }
+ thead {
+  display:table-header-group
+ }
+ img,
+ tr {
+  page-break-inside:avoid
+ }
+ h2,
+ h3,
+ p {
+  orphans:3;
+  widows:3
+ }
+ h2,
+ h3 {
+  page-break-after:avoid
+ }
+ @page {
+  size:a3
+ }
+ body {
+  min-width:992px!important
+ }
+ .container {
+  min-width:992px!important
+ }
+ .navbar {
+  display:none
+ }
+ .badge {
+  border:1px solid #222
+ }
+ .table {
+  border-collapse:collapse!important
+ }
+ .table td,
+ .table th {
+  background-color:#fff!important
+ }
+ .table-bordered td,
+ .table-bordered th {
+  border:1px solid #dee2e6!important
+ }
+ .table-dark {
+  color:inherit
+ }
+ .table-dark tbody+tbody,
+ .table-dark td,
+ .table-dark th,
+ .table-dark thead th {
+  border-color:#495057
+ }
+ .table .thead-dark th {
+  color:inherit;
+  border-color:#495057
+ }
+}
diff --git a/src/assets/css/themes/nord.css b/src/assets/css/themes/nord.css
new file mode 100644 (file)
index 0000000..b85d77d
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+This CSS contains a modified version of Bootstrap's CSS
+Bootstrap's License can be found here: https://github.com/twbs/bootstrap/blob/main/LICENSE
+
+This CSS contains the Nord color scheme made by Arctic Ice Studio & Sven Greb
+Nord's License can be found here: https://github.com/arcticicestudio/nord/blob/develop/LICENSE.md
+
+The modifications to Bootstrap's CSS were done by SaberTooth Studios Games
+The github repository containing the source code of this CSS can be found here: https://github.com/SaberTooth-Studios/NordTheme-Bootstrap/
+*/
+
+:root{--blue:#88C0D0;--indigo:#5E81AC;--purple:#B48EAD;--pink:#B48EAD;--red:#BF616A;--orange:#D08770;--yellow:#EBCB8B;--green:#A3BE8C;--teal:#8FBCBB;--cyan:#81A1C1;--white:#ECEFF4;--gray:#4C566A;--gray-dark:#2E3440;--primary:#88C0D0;--secondary:#4C566A;--success:#A3BE8C;--info:#81A1C1;--warning:#EBCB8B;--danger:#BF616A;--light:#3B4252;--dark:#8c94a4;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:992px;--breakpoint-xl:1200px;--font-family-sans-serif:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-family-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(46,52,64,0)}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#eceff4;text-align:left;background-color:#2e3440}[tabindex="-1"]:focus:not(:focus-visible){outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}p{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;cursor:help;border-bottom:0;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#88c0d0;text-decoration:none;background-color:transparent}a:hover{color:#51a3ba;text-decoration:underline}a:not([href]){color:inherit;text-decoration:none}a:not([href]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em}pre{margin-top:0;margin-bottom:1rem;overflow:auto;-ms-overflow-style:scrollbar}figure{margin:0 0 1rem}img{vertical-align:middle;border-style:none}svg{overflow:hidden;vertical-align:middle}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#8c94a4;text-align:left;caption-side:bottom}th{text-align:inherit}label{display:inline-block;margin-bottom:.5rem}button{border-radius:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{display:block;width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}@media (max-width:1200px){legend{font-size:calc(1.275rem + .3vw)}}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item;cursor:pointer}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-weight:500;line-height:1.2}.h1,h1{font-size:2.5rem}@media (max-width:1200px){.h1,h1{font-size:calc(1.375rem + 1.5vw)}}.h2,h2{font-size:2rem}@media (max-width:1200px){.h2,h2{font-size:calc(1.325rem + .9vw)}}.h3,h3{font-size:1.75rem}@media (max-width:1200px){.h3,h3{font-size:calc(1.3rem + .6vw)}}.h4,h4{font-size:1.5rem}@media (max-width:1200px){.h4,h4{font-size:calc(1.275rem + .3vw)}}.h5,h5{font-size:1.25rem}.h6,h6{font-size:1rem}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:6rem;font-weight:300;line-height:1.2}@media (max-width:1200px){.display-1{font-size:calc(1.725rem + 5.7vw)}}.display-2{font-size:5.5rem;font-weight:300;line-height:1.2}@media (max-width:1200px){.display-2{font-size:calc(1.675rem + 5.1vw)}}.display-3{font-size:4.5rem;font-weight:300;line-height:1.2}@media (max-width:1200px){.display-3{font-size:calc(1.575rem + 3.9vw)}}.display-4{font-size:3.5rem;font-weight:300;line-height:1.2}@media (max-width:1200px){.display-4{font-size:calc(1.475rem + 2.7vw)}}hr{margin-top:1rem;margin-bottom:1rem;border:0;border-top:1px solid rgba(46,52,64,.1)}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#eceff4}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote-footer{display:block;font-size:80%;color:#8c94a4}.blockquote-footer::before{content:"\2014\00A0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#2e3440;border:1px solid #d8dee9;border-radius:.25rem;box-shadow:0 1px 2px rgba(46,52,64,.075);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#4c566a}code{font-size:87.5%;color:#b48ead;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:87.5%;color:#eceff4;background-color:#2e3440;border-radius:.2rem;box-shadow:inset 0 -.1rem 0 rgba(46,52,64,.25)}kbd kbd{padding:0;font-size:100%;font-weight:700;box-shadow:none}pre{display:block;font-size:87.5%;color:#2e3440}pre code{font-size:inherit;color:inherit;word-break:normal}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:992px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.container-fluid,.container-lg,.container-md,.container-sm,.container-xl{width:100%;padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}.row{display:flex;flex-wrap:wrap;margin-right:-15px;margin-left:-15px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;padding-right:15px;padding-left:15px}.col{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-1>*{flex:0 0 100%;max-width:100%}.row-cols-2>*{flex:0 0 50%;max-width:50%}.row-cols-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-4>*{flex:0 0 25%;max-width:25%}.row-cols-5>*{flex:0 0 20%;max-width:20%}.row-cols-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-auto{flex:0 0 auto;width:auto;max-width:100%}.col-1{flex:0 0 8.33333%;max-width:8.33333%}.col-2{flex:0 0 16.66667%;max-width:16.66667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.33333%;max-width:33.33333%}.col-5{flex:0 0 41.66667%;max-width:41.66667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.33333%;max-width:58.33333%}.col-8{flex:0 0 66.66667%;max-width:66.66667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.33333%;max-width:83.33333%}.col-11{flex:0 0 91.66667%;max-width:91.66667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-sm-1>*{flex:0 0 100%;max-width:100%}.row-cols-sm-2>*{flex:0 0 50%;max-width:50%}.row-cols-sm-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-sm-4>*{flex:0 0 25%;max-width:25%}.row-cols-sm-5>*{flex:0 0 20%;max-width:20%}.row-cols-sm-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-auto{flex:0 0 auto;width:auto;max-width:100%}.col-sm-1{flex:0 0 8.33333%;max-width:8.33333%}.col-sm-2{flex:0 0 16.66667%;max-width:16.66667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.33333%;max-width:33.33333%}.col-sm-5{flex:0 0 41.66667%;max-width:41.66667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.33333%;max-width:58.33333%}.col-sm-8{flex:0 0 66.66667%;max-width:66.66667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.33333%;max-width:83.33333%}.col-sm-11{flex:0 0 91.66667%;max-width:91.66667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-md-1>*{flex:0 0 100%;max-width:100%}.row-cols-md-2>*{flex:0 0 50%;max-width:50%}.row-cols-md-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-md-4>*{flex:0 0 25%;max-width:25%}.row-cols-md-5>*{flex:0 0 20%;max-width:20%}.row-cols-md-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-md-auto{flex:0 0 auto;width:auto;max-width:100%}.col-md-1{flex:0 0 8.33333%;max-width:8.33333%}.col-md-2{flex:0 0 16.66667%;max-width:16.66667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.33333%;max-width:33.33333%}.col-md-5{flex:0 0 41.66667%;max-width:41.66667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.33333%;max-width:58.33333%}.col-md-8{flex:0 0 66.66667%;max-width:66.66667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.33333%;max-width:83.33333%}.col-md-11{flex:0 0 91.66667%;max-width:91.66667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}@media (min-width:992px){.col-lg{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-lg-1>*{flex:0 0 100%;max-width:100%}.row-cols-lg-2>*{flex:0 0 50%;max-width:50%}.row-cols-lg-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-lg-4>*{flex:0 0 25%;max-width:25%}.row-cols-lg-5>*{flex:0 0 20%;max-width:20%}.row-cols-lg-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-auto{flex:0 0 auto;width:auto;max-width:100%}.col-lg-1{flex:0 0 8.33333%;max-width:8.33333%}.col-lg-2{flex:0 0 16.66667%;max-width:16.66667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.33333%;max-width:33.33333%}.col-lg-5{flex:0 0 41.66667%;max-width:41.66667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.33333%;max-width:58.33333%}.col-lg-8{flex:0 0 66.66667%;max-width:66.66667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.33333%;max-width:83.33333%}.col-lg-11{flex:0 0 91.66667%;max-width:91.66667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;min-width:0;max-width:100%}.row-cols-xl-1>*{flex:0 0 100%;max-width:100%}.row-cols-xl-2>*{flex:0 0 50%;max-width:50%}.row-cols-xl-3>*{flex:0 0 33.33333%;max-width:33.33333%}.row-cols-xl-4>*{flex:0 0 25%;max-width:25%}.row-cols-xl-5>*{flex:0 0 20%;max-width:20%}.row-cols-xl-6>*{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-auto{flex:0 0 auto;width:auto;max-width:100%}.col-xl-1{flex:0 0 8.33333%;max-width:8.33333%}.col-xl-2{flex:0 0 16.66667%;max-width:16.66667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.33333%;max-width:33.33333%}.col-xl-5{flex:0 0 41.66667%;max-width:41.66667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.33333%;max-width:58.33333%}.col-xl-8{flex:0 0 66.66667%;max-width:66.66667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.33333%;max-width:83.33333%}.col-xl-11{flex:0 0 91.66667%;max-width:91.66667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.table{width:100%;margin-bottom:1rem;color:#eceff4}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #d8dee9}.table thead th{vertical-align:bottom;border-bottom:2px solid #d8dee9}.table tbody+tbody{border-top:2px solid #d8dee9}.table-sm td,.table-sm th{padding:.3rem}.table-bordered{border:1px solid #d8dee9}.table-bordered td,.table-bordered th{border:1px solid #d8dee9}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(odd){background-color:rgba(46,52,64,.05)}.table-hover tbody tr:hover{color:#eceff4;background-color:rgba(46,52,64,.075)}.table-primary,.table-primary>td,.table-primary>th{background-color:#81b5c4}.table-primary tbody+tbody,.table-primary td,.table-primary th,.table-primary thead th{border-color:#88c0d0}.table-hover .table-primary:hover{background-color:#70abbc}.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#70abbc}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#4a5367}.table-secondary tbody+tbody,.table-secondary td,.table-secondary th,.table-secondary thead th{border-color:#4c566a}.table-hover .table-secondary:hover{background-color:#3f4758}.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#3f4758}.table-success,.table-success>td,.table-success>th{background-color:#9ab386}.table-success tbody+tbody,.table-success td,.table-success th,.table-success thead th{border-color:#a3be8c}.table-hover .table-success:hover{background-color:#8da976}.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#8da976}.table-info,.table-info>td,.table-info>th{background-color:#7a98b7}.table-info tbody+tbody,.table-info td,.table-info th,.table-info thead th{border-color:#81a1c1}.table-hover .table-info:hover{background-color:#698bae}.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#698bae}.table-warning,.table-warning>td,.table-warning>th{background-color:#dcbf85}.table-warning tbody+tbody,.table-warning td,.table-warning th,.table-warning thead th{border-color:#ebcb8b}.table-hover .table-warning:hover{background-color:#d6b571}.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#d6b571}.table-danger,.table-danger>td,.table-danger>th{background-color:#b35d67}.table-danger tbody+tbody,.table-danger td,.table-danger th,.table-danger thead th{border-color:#bf616a}.table-hover .table-danger:hover{background-color:#a84f59}.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#a84f59}.table-light,.table-light>td,.table-light>th{background-color:#3a4151}.table-light tbody+tbody,.table-light td,.table-light th,.table-light thead th{border-color:#3b4252}.table-hover .table-light:hover{background-color:#2f3542}.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#2f3542}.table-dark,.table-dark>td,.table-dark>th{background-color:#848c9c}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#8c94a4}.table-hover .table-dark:hover{background-color:#767f91}.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#767f91}.table-active,.table-active>td,.table-active>th{background-color:rgba(46,52,64,.075)}.table-hover .table-active:hover{background-color:rgba(35,40,49,.075)}.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:rgba(35,40,49,.075)}.table .thead-dark th{color:#eceff4;background-color:#2e3440;border-color:#3e4656}.table .thead-light th{color:#3b4252;background-color:#e5e9f0;border-color:#d8dee9}.table-dark{color:#eceff4;background-color:#2e3440}.table-dark td,.table-dark th,.table-dark thead th{border-color:#3e4656}.table-dark.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(236,239,244,.05)}.table-dark.table-hover tbody tr:hover{color:#eceff4;background-color:rgba(236,239,244,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-md>.table-bordered{border:0}}@media (max-width:991.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive-xl>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch}.table-responsive>.table-bordered{border:0}.form-control{display:block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#88c0d0;background-color:#4c566a;background-clip:padding-box;border:1px solid #4c566a;border-radius:.25rem;box-shadow:inset 0 1px 1px rgba(46,52,64,.075);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:-moz-focusring{color:transparent;text-shadow:0 0 0 #88c0d0}.form-control:focus{color:#88c0d0;background-color:#4c566a;border-color:#e3f0f4;outline:0;box-shadow:inset 0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(136,192,208,.25)}.form-control::placeholder{color:#8c94a4;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#3b4252;opacity:1}input[type=date].form-control,input[type=datetime-local].form-control,input[type=month].form-control,input[type=time].form-control{appearance:none}select.form-control:focus::-ms-value{color:#88c0d0;background-color:#4c566a}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.375rem + 1px);padding-bottom:calc(.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + 1px);padding-bottom:calc(.5rem + 1px);font-size:1.25rem;line-height:1.5}.col-form-label-sm{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.5}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;font-size:1rem;line-height:1.5;color:#eceff4;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.5em + .5rem + 2px);padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.form-control-lg{height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}select.form-control[multiple],select.form-control[size]{height:auto}textarea.form-control{height:auto}.form-group{margin-bottom:1rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-5px;margin-left:-5px}.form-row>.col,.form-row>[class*=col-]{padding-right:5px;padding-left:5px}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{color:#8c94a4}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#a3be8c}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#2e3440;background-color:rgba(163,190,140,.9);border-radius:.25rem}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:#a3be8c;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23A3BE8C' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#a3be8c;box-shadow:0 0 0 .2rem rgba(163,190,140,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-valid,.was-validated .custom-select:valid{border-color:#a3be8c;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%2388C0D0' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%23A3BE8C' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e") #4c566a no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-valid:focus,.was-validated .custom-select:valid:focus{border-color:#a3be8c;box-shadow:0 0 0 .2rem rgba(163,190,140,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#a3be8c}.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.was-validated .custom-control-input:valid~.custom-control-label{color:#a3be8c}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{border-color:#a3be8c}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{border-color:#bdd0ad;background:#bdd0ad linear-gradient(180deg,#a8b99c,#bdd0ad) repeat-x}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(163,190,140,.25)}.custom-control-input.is-valid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:valid:focus:not(:checked)~.custom-control-label::before{border-color:#a3be8c}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#a3be8c}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{border-color:#a3be8c;box-shadow:0 0 0 .2rem rgba(163,190,140,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#bf616a}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;line-height:1.5;color:#eceff4;background-color:rgba(191,97,106,.9);border-radius:.25rem}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:#bf616a;padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23BF616A' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23BF616A' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#bf616a;box-shadow:0 0 0 .2rem rgba(191,97,106,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.custom-select.is-invalid,.was-validated .custom-select:invalid{border-color:#bf616a;padding-right:calc(.75em + 2.3125rem);background:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%2388C0D0' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px,url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23BF616A' viewBox='0 0 12 12'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23BF616A' stroke='none'/%3e%3c/svg%3e") #4c566a no-repeat center right 1.75rem/calc(.75em + .375rem) calc(.75em + .375rem)}.custom-select.is-invalid:focus,.was-validated .custom-select:invalid:focus{border-color:#bf616a;box-shadow:0 0 0 .2rem rgba(191,97,106,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#bf616a}.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.was-validated .custom-control-input:invalid~.custom-control-label{color:#bf616a}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{border-color:#bf616a}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{border-color:#ce858c;background:#ce858c linear-gradient(180deg,#b67981,#ce858c) repeat-x}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 .2rem rgba(191,97,106,.25)}.custom-control-input.is-invalid:focus:not(:checked)~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus:not(:checked)~.custom-control-label::before{border-color:#bf616a}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#bf616a}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{border-color:#bf616a;box-shadow:0 0 0 .2rem rgba(191,97,106,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex:0 0 auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;flex-shrink:0;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.btn{display:inline-block;font-weight:400;color:#eceff4;text-align:center;vertical-align:middle;user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;line-height:1.5;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.btn:hover{color:#eceff4;text-decoration:none}.btn.focus,.btn:focus{outline:0;box-shadow:0 0 0 .2rem rgba(136,192,208,.25)}.btn.disabled,.btn:disabled{opacity:.65;box-shadow:none}.btn:not(:disabled):not(.disabled){cursor:pointer}.btn:not(:disabled):not(.disabled).active,.btn:not(:disabled):not(.disabled):active{box-shadow:inset 0 3px 5px rgba(46,52,64,.125)}.btn:not(:disabled):not(.disabled).active:focus,.btn:not(:disabled):not(.disabled):active:focus{box-shadow:0 0 0 .2rem rgba(136,192,208,.25),inset 0 3px 5px rgba(46,52,64,.125)}a.btn.disabled,fieldset:disabled a.btn{pointer-events:none}.btn-primary{color:#2e3440;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x;border-color:#88c0d0;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-primary:hover{color:#2e3440;background:#6db1c5 linear-gradient(180deg,#639fb1,#6db1c5) repeat-x;border-color:#63adc2}.btn-primary.focus,.btn-primary:focus{color:#2e3440;background:#6db1c5 linear-gradient(180deg,#639fb1,#6db1c5) repeat-x;border-color:#63adc2;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(123,171,186,.5)}.btn-primary.disabled,.btn-primary:disabled{color:#2e3440;background-color:#88c0d0;border-color:#88c0d0;background-image:none}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle{color:#2e3440;background-color:#63adc2;background-image:none;border-color:#5aa8be}.btn-primary:not(:disabled):not(.disabled).active:focus,.btn-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(123,171,186,.5)}.btn-secondary{color:#eceff4;background:#4c566a linear-gradient(180deg,#485164,#4c566a) repeat-x;border-color:#4c566a;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-secondary:hover{color:#eceff4;background:#3c4454 linear-gradient(180deg,#3a4251,#3c4454) repeat-x;border-color:#373e4c}.btn-secondary.focus,.btn-secondary:focus{color:#eceff4;background:#3c4454 linear-gradient(180deg,#3a4251,#3c4454) repeat-x;border-color:#373e4c;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(100,109,127,.5)}.btn-secondary.disabled,.btn-secondary:disabled{color:#eceff4;background-color:#4c566a;border-color:#4c566a;background-image:none}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle{color:#eceff4;background-color:#373e4c;background-image:none;border-color:#313845}.btn-secondary:not(:disabled):not(.disabled).active:focus,.btn-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(100,109,127,.5)}.btn-success{color:#2e3440;background:#a3be8c linear-gradient(180deg,#91a981,#a3be8c) repeat-x;border-color:#a3be8c;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-success:hover{color:#2e3440;background:#8fb074 linear-gradient(180deg,#819e6c,#8fb074) repeat-x;border-color:#89ac6b}.btn-success.focus,.btn-success:focus{color:#2e3440;background:#8fb074 linear-gradient(180deg,#819e6c,#8fb074) repeat-x;border-color:#89ac6b;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(145,169,129,.5)}.btn-success.disabled,.btn-success:disabled{color:#2e3440;background-color:#a3be8c;border-color:#a3be8c;background-image:none}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle{color:#2e3440;background-color:#89ac6b;background-image:none;border-color:#82a763}.btn-success:not(:disabled):not(.disabled).active:focus,.btn-success:not(:disabled):not(.disabled):active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(145,169,129,.5)}.btn-info{color:#2e3440;background:#81a1c1 linear-gradient(180deg,#7591ae,#81a1c1) repeat-x;border-color:#81a1c1;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-info:hover{color:#eceff4;background:#678eb4 linear-gradient(180deg,#5f80a3,#678eb4) repeat-x;border-color:#5f88b0}.btn-info.focus,.btn-info:focus{color:#eceff4;background:#678eb4 linear-gradient(180deg,#5f80a3,#678eb4) repeat-x;border-color:#5f88b0;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(117,145,174,.5)}.btn-info.disabled,.btn-info:disabled{color:#2e3440;background-color:#81a1c1;border-color:#81a1c1;background-image:none}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle{color:#eceff4;background-color:#5f88b0;background-image:none;border-color:#5681ac}.btn-info:not(:disabled):not(.disabled).active:focus,.btn-info:not(:disabled):not(.disabled):active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(117,145,174,.5)}.btn-warning{color:#2e3440;background:#ebcb8b linear-gradient(180deg,#cfb480,#ebcb8b) repeat-x;border-color:#ebcb8b;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-warning:hover{color:#2e3440;background:#e5bc6a linear-gradient(180deg,#caa864,#e5bc6a) repeat-x;border-color:#e4b860}.btn-warning.focus,.btn-warning:focus{color:#2e3440;background:#e5bc6a linear-gradient(180deg,#caa864,#e5bc6a) repeat-x;border-color:#e4b860;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(207,180,128,.5)}.btn-warning.disabled,.btn-warning:disabled{color:#2e3440;background-color:#ebcb8b;border-color:#ebcb8b;background-image:none}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle{color:#2e3440;background-color:#e4b860;background-image:none;border-color:#e2b355}.btn-warning:not(:disabled):not(.disabled).active:focus,.btn-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(207,180,128,.5)}.btn-danger{color:#eceff4;background:#bf616a linear-gradient(180deg,#a95a64,#bf616a) repeat-x;border-color:#bf616a;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-danger:hover{color:#eceff4;background:#b24852 linear-gradient(180deg,#9e454f,#b24852) repeat-x;border-color:#a9444e}.btn-danger.focus,.btn-danger:focus{color:#eceff4;background:#b24852 linear-gradient(180deg,#9e454f,#b24852) repeat-x;border-color:#a9444e;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(198,118,127,.5)}.btn-danger.disabled,.btn-danger:disabled{color:#eceff4;background-color:#bf616a;border-color:#bf616a;background-image:none}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle{color:#eceff4;background-color:#a9444e;background-image:none;border-color:#a0414a}.btn-danger:not(:disabled):not(.disabled).active:focus,.btn-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(198,118,127,.5)}.btn-light{color:#eceff4;background:#3b4252 linear-gradient(180deg,#39404f,#3b4252) repeat-x;border-color:#3b4252;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-light:hover{color:#eceff4;background:#2b303c linear-gradient(180deg,#2b313c,#2b303c) repeat-x;border-color:#262a34}.btn-light.focus,.btn-light:focus{color:#eceff4;background:#2b303c linear-gradient(180deg,#2b313c,#2b303c) repeat-x;border-color:#262a34;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(86,92,106,.5)}.btn-light.disabled,.btn-light:disabled{color:#eceff4;background-color:#3b4252;border-color:#3b4252;background-image:none}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle{color:#eceff4;background-color:#262a34;background-image:none;border-color:#20242d}.btn-light:not(:disabled):not(.disabled).active:focus,.btn-light:not(:disabled):not(.disabled):active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(86,92,106,.5)}.btn-dark{color:#eceff4;background:#8c94a4 linear-gradient(180deg,#7e8695,#8c94a4) repeat-x;border-color:#8c94a4;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075)}.btn-dark:hover{color:#eceff4;background:#778093 linear-gradient(180deg,#6c7587,#778093) repeat-x;border-color:#707a8d}.btn-dark.focus,.btn-dark:focus{color:#eceff4;background:#778093 linear-gradient(180deg,#6c7587,#778093) repeat-x;border-color:#707a8d;box-shadow:inset 0 1px 0 rgba(236,239,244,.15),0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(154,162,176,.5)}.btn-dark.disabled,.btn-dark:disabled{color:#eceff4;background-color:#8c94a4;border-color:#8c94a4;background-image:none}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle{color:#eceff4;background-color:#707a8d;background-image:none;border-color:#6a7386}.btn-dark:not(:disabled):not(.disabled).active:focus,.btn-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(154,162,176,.5)}.btn-outline-primary{color:#88c0d0;border-color:#88c0d0}.btn-outline-primary:hover{color:#2e3440;background-color:#88c0d0;border-color:#88c0d0}.btn-outline-primary.focus,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(136,192,208,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{color:#88c0d0;background-color:transparent}.btn-outline-primary:not(:disabled):not(.disabled).active,.btn-outline-primary:not(:disabled):not(.disabled):active,.show>.btn-outline-primary.dropdown-toggle{color:#2e3440;background-color:#88c0d0;border-color:#88c0d0}.btn-outline-primary:not(:disabled):not(.disabled).active:focus,.btn-outline-primary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-primary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(136,192,208,.5)}.btn-outline-secondary{color:#4c566a;border-color:#4c566a}.btn-outline-secondary:hover{color:#eceff4;background-color:#4c566a;border-color:#4c566a}.btn-outline-secondary.focus,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(76,86,106,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{color:#4c566a;background-color:transparent}.btn-outline-secondary:not(:disabled):not(.disabled).active,.btn-outline-secondary:not(:disabled):not(.disabled):active,.show>.btn-outline-secondary.dropdown-toggle{color:#eceff4;background-color:#4c566a;border-color:#4c566a}.btn-outline-secondary:not(:disabled):not(.disabled).active:focus,.btn-outline-secondary:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-secondary.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(76,86,106,.5)}.btn-outline-success{color:#a3be8c;border-color:#a3be8c}.btn-outline-success:hover{color:#2e3440;background-color:#a3be8c;border-color:#a3be8c}.btn-outline-success.focus,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(163,190,140,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{color:#a3be8c;background-color:transparent}.btn-outline-success:not(:disabled):not(.disabled).active,.btn-outline-success:not(:disabled):not(.disabled):active,.show>.btn-outline-success.dropdown-toggle{color:#2e3440;background-color:#a3be8c;border-color:#a3be8c}.btn-outline-success:not(:disabled):not(.disabled).active:focus,.btn-outline-success:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-success.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(163,190,140,.5)}.btn-outline-info{color:#81a1c1;border-color:#81a1c1}.btn-outline-info:hover{color:#2e3440;background-color:#81a1c1;border-color:#81a1c1}.btn-outline-info.focus,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(129,161,193,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{color:#81a1c1;background-color:transparent}.btn-outline-info:not(:disabled):not(.disabled).active,.btn-outline-info:not(:disabled):not(.disabled):active,.show>.btn-outline-info.dropdown-toggle{color:#2e3440;background-color:#81a1c1;border-color:#81a1c1}.btn-outline-info:not(:disabled):not(.disabled).active:focus,.btn-outline-info:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-info.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(129,161,193,.5)}.btn-outline-warning{color:#ebcb8b;border-color:#ebcb8b}.btn-outline-warning:hover{color:#2e3440;background-color:#ebcb8b;border-color:#ebcb8b}.btn-outline-warning.focus,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(235,203,139,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{color:#ebcb8b;background-color:transparent}.btn-outline-warning:not(:disabled):not(.disabled).active,.btn-outline-warning:not(:disabled):not(.disabled):active,.show>.btn-outline-warning.dropdown-toggle{color:#2e3440;background-color:#ebcb8b;border-color:#ebcb8b}.btn-outline-warning:not(:disabled):not(.disabled).active:focus,.btn-outline-warning:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-warning.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(235,203,139,.5)}.btn-outline-danger{color:#bf616a;border-color:#bf616a}.btn-outline-danger:hover{color:#eceff4;background-color:#bf616a;border-color:#bf616a}.btn-outline-danger.focus,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(191,97,106,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{color:#bf616a;background-color:transparent}.btn-outline-danger:not(:disabled):not(.disabled).active,.btn-outline-danger:not(:disabled):not(.disabled):active,.show>.btn-outline-danger.dropdown-toggle{color:#eceff4;background-color:#bf616a;border-color:#bf616a}.btn-outline-danger:not(:disabled):not(.disabled).active:focus,.btn-outline-danger:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-danger.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(191,97,106,.5)}.btn-outline-light{color:#3b4252;border-color:#3b4252}.btn-outline-light:hover{color:#eceff4;background-color:#3b4252;border-color:#3b4252}.btn-outline-light.focus,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(59,66,82,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{color:#3b4252;background-color:transparent}.btn-outline-light:not(:disabled):not(.disabled).active,.btn-outline-light:not(:disabled):not(.disabled):active,.show>.btn-outline-light.dropdown-toggle{color:#eceff4;background-color:#3b4252;border-color:#3b4252}.btn-outline-light:not(:disabled):not(.disabled).active:focus,.btn-outline-light:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-light.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(59,66,82,.5)}.btn-outline-dark{color:#8c94a4;border-color:#8c94a4}.btn-outline-dark:hover{color:#eceff4;background-color:#8c94a4;border-color:#8c94a4}.btn-outline-dark.focus,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(140,148,164,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{color:#8c94a4;background-color:transparent}.btn-outline-dark:not(:disabled):not(.disabled).active,.btn-outline-dark:not(:disabled):not(.disabled):active,.show>.btn-outline-dark.dropdown-toggle{color:#eceff4;background-color:#8c94a4;border-color:#8c94a4}.btn-outline-dark:not(:disabled):not(.disabled).active:focus,.btn-outline-dark:not(:disabled):not(.disabled):active:focus,.show>.btn-outline-dark.dropdown-toggle:focus{box-shadow:inset 0 3px 5px rgba(46,52,64,.125),0 0 0 .2rem rgba(140,148,164,.5)}.btn-link{font-weight:400;color:#88c0d0;text-decoration:none}.btn-link:hover{color:#51a3ba;text-decoration:underline}.btn-link.focus,.btn-link:focus{text-decoration:underline}.btn-link.disabled,.btn-link:disabled{color:#8c94a4;pointer-events:none}.btn-group-lg>.btn,.btn-lg{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.btn-group-sm>.btn,.btn-sm{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.btn-block{display:block;width:100%}.btn-block+.btn-block{margin-top:.5rem}input[type=button].btn-block,input[type=reset].btn-block,input[type=submit].btn-block{width:100%}.fade{transition:opacity .15s linear}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{position:relative;height:0;overflow:hidden;transition:height .35s ease}.dropdown,.dropleft,.dropright,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:10rem;padding:.5rem 0;margin:.125rem 0 0;font-size:1rem;color:#eceff4;text-align:left;list-style:none;background-color:#3b4252;background-clip:padding-box;border:1px solid rgba(46,52,64,.15);border-radius:.25rem;box-shadow:0 .5rem 1rem rgba(46,52,64,.175)}.dropdown-menu-left{right:auto;left:0}.dropdown-menu-right{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-left{right:auto;left:0}.dropdown-menu-sm-right{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-left{right:auto;left:0}.dropdown-menu-md-right{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-left{right:auto;left:0}.dropdown-menu-lg-right{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-left{right:auto;left:0}.dropdown-menu-xl-right{right:0;left:auto}}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropright .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-toggle::after{vertical-align:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropleft .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropleft .dropdown-toggle::after{display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-toggle::before{vertical-align:0}.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=top]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid #e5e9f0}.dropdown-item{display:block;width:100%;padding:.25rem 1.5rem;clear:both;font-weight:400;color:#eceff4;text-align:inherit;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:#dce1eb;text-decoration:none;background:#4c566a linear-gradient(180deg,#485164,#4c566a) repeat-x}.dropdown-item.active,.dropdown-item:active{color:#2e3440;text-decoration:none;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x}.dropdown-item.disabled,.dropdown-item:disabled{color:#4c566a;pointer-events:none;background-color:transparent;background-image:none}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1.5rem;margin-bottom:0;font-size:.875rem;color:#4c566a;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1.5rem;color:#eceff4}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn:hover,.btn-group>.btn:hover{z-index:1}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group.show .dropdown-toggle{box-shadow:inset 0 3px 5px rgba(46,52,64,.125)}.btn-group.show .dropdown-toggle.btn-link{box-shadow:none}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control,.input-group>.form-control-plaintext{position:relative;flex:1 1 auto;width:1%;min-width:0;margin-bottom:0}.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.input-group>.form-control-plaintext+.custom-file,.input-group>.form-control-plaintext+.custom-select,.input-group>.form-control-plaintext+.form-control{margin-left:-1px}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.custom-file{display:flex;align-items:center}.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.custom-file:not(:first-child) .custom-file-label{border-top-left-radius:0;border-bottom-left-radius:0}.input-group-append,.input-group-prepend{display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-append .btn:focus,.input-group-prepend .btn:focus{z-index:3}.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text{margin-left:-1px}.input-group-prepend{margin-right:-1px}.input-group-append{margin-left:-1px}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;margin-bottom:0;font-size:1rem;font-weight:400;line-height:1.5;color:#88c0d0;text-align:center;white-space:nowrap;background-color:#4c566a;border:1px solid #4c566a;border-radius:.25rem}.input-group-text input[type=checkbox],.input-group-text input[type=radio]{margin-top:0}.input-group-lg>.custom-select,.input-group-lg>.form-control:not(textarea){height:calc(1.5em + 1rem + 2px)}.input-group-lg>.custom-select,.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{padding:.5rem 1rem;font-size:1.25rem;line-height:1.5;border-radius:.3rem}.input-group-sm>.custom-select,.input-group-sm>.form-control:not(textarea){height:calc(1.5em + .5rem + 2px)}.input-group-sm>.custom-select,.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{padding:.25rem .5rem;font-size:.875rem;line-height:1.5;border-radius:.2rem}.input-group-lg>.custom-select,.input-group-sm>.custom-select{padding-right:1.75rem}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.5rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;left:0;z-index:-1;width:1rem;height:1.25rem;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#2e3440;border-color:#88c0d0;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x;box-shadow:none}.custom-control-input:focus~.custom-control-label::before{box-shadow:inset 0 1px 1px rgba(46,52,64,.075),0 0 0 .2rem rgba(136,192,208,.25)}.custom-control-input:focus:not(:checked)~.custom-control-label::before{border-color:#e3f0f4}.custom-control-input:not(:disabled):active~.custom-control-label::before{color:#2e3440;background-color:#fff;border-color:#fff;box-shadow:none}.custom-control-input:disabled~.custom-control-label,.custom-control-input[disabled]~.custom-control-label{color:#8c94a4}.custom-control-input:disabled~.custom-control-label::before,.custom-control-input[disabled]~.custom-control-label::before{background-color:#3b4252}.custom-control-label{position:relative;margin-bottom:0;color:#88c0d0;vertical-align:top;cursor:#88c0d0}.custom-control-label::before{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;pointer-events:none;content:"";background-color:#4c566a;border:#8c94a4 solid 1px;box-shadow:inset 0 1px 1px rgba(46,52,64,.075)}.custom-control-label::after{position:absolute;top:.25rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:"";background:no-repeat 50%/50% 50%}.custom-checkbox .custom-control-label::before{border-radius:.25rem}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath fill='%232E3440' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{border-color:#88c0d0;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x;box-shadow:none}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='4' viewBox='0 0 4 4'%3e%3cpath stroke='%232E3440' d='M0 2h4'/%3e%3c/svg%3e")}.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(136,192,208,.5)}.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before{background-color:rgba(136,192,208,.5)}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%232E3440'/%3e%3c/svg%3e")}.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(136,192,208,.5)}.custom-switch{padding-left:2.25rem}.custom-switch .custom-control-label::before{left:-2.25rem;width:1.75rem;pointer-events:all;border-radius:.5rem}.custom-switch .custom-control-label::after{top:calc(.25rem + 2px);left:calc(-2.25rem + 2px);width:calc(1rem - 4px);height:calc(1rem - 4px);background-color:#8c94a4;border-radius:.5rem;transition:transform .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.custom-switch .custom-control-input:checked~.custom-control-label::after{background-color:#4c566a;transform:translateX(.75rem)}.custom-switch .custom-control-input:disabled:checked~.custom-control-label::before{background-color:rgba(136,192,208,.5)}.custom-select{display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);padding:.375rem 1.75rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#88c0d0;vertical-align:middle;background:#4c566a url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='4' height='5' viewBox='0 0 4 5'%3e%3cpath fill='%2388C0D0' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e") no-repeat right .75rem center/8px 10px;border:1px solid #4c566a;border-radius:.25rem;box-shadow:inset 0 1px 2px rgba(46,52,64,.075);appearance:none}.custom-select:focus{border-color:#e3f0f4;outline:0;box-shadow:inset 0 1px 2px rgba(46,52,64,.075),0 0 0 .2rem rgba(136,192,208,.25)}.custom-select:focus::-ms-value{color:#88c0d0;background-color:#4c566a}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.75rem;background-image:none}.custom-select:disabled{color:#4c566a;background-color:#e5e9f0}.custom-select::-ms-expand{display:none}.custom-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #88c0d0}.custom-select-sm{height:calc(1.5em + .5rem + 2px);padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem}.custom-select-lg{height:calc(1.5em + 1rem + 2px);padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.custom-file{position:relative;display:inline-block;width:100%;height:calc(1.5em + .75rem + 2px);margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;height:calc(1.5em + .75rem + 2px);margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#e3f0f4;box-shadow:0 0 0 .2rem rgba(136,192,208,.25)}.custom-file-input:disabled~.custom-file-label,.custom-file-input[disabled]~.custom-file-label{background-color:#3b4252}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-input~.custom-file-label[data-browse]::after{content:attr(data-browse)}.custom-file-label{position:absolute;top:0;right:0;left:0;z-index:1;height:calc(1.5em + .75rem + 2px);padding:.375rem .75rem;font-weight:400;line-height:1.5;color:#88c0d0;background-color:#4c566a;border:1px solid #4c566a;border-radius:.25rem;box-shadow:inset 0 1px 1px rgba(46,52,64,.075)}.custom-file-label::after{position:absolute;top:0;right:0;bottom:0;z-index:3;display:block;height:calc(1.5em + .75rem);padding:.375rem .75rem;line-height:1.5;color:#88c0d0;content:"Browse";background:#4c566a linear-gradient(180deg,#485164,#4c566a) repeat-x;border-left:inherit;border-radius:0 .25rem .25rem 0}.custom-range{width:100%;height:1.4rem;padding:0;background-color:transparent;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #2e3440,0 0 0 .2rem rgba(136,192,208,.25)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #2e3440,0 0 0 .2rem rgba(136,192,208,.25)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #2e3440,0 0 0 .2rem rgba(136,192,208,.25)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(46,52,64,.1);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}.custom-range::-webkit-slider-thumb:active{background:#fff linear-gradient(180deg,#e0e1e2,#fff) repeat-x}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#d8dee9;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(46,52,64,.1)}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(46,52,64,.1);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}.custom-range::-moz-range-thumb:active{background:#fff linear-gradient(180deg,#e0e1e2,#fff) repeat-x}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#d8dee9;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(46,52,64,.1)}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(46,52,64,.1);transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}.custom-range::-ms-thumb:active{background:#fff linear-gradient(180deg,#e0e1e2,#fff) repeat-x}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem;box-shadow:inset 0 .25rem .25rem rgba(46,52,64,.1)}.custom-range::-ms-fill-lower{background-color:#d8dee9;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:15px;background-color:#d8dee9;border-radius:1rem}.custom-range:disabled::-webkit-slider-thumb{background-color:#d8dee9}.custom-range:disabled::-webkit-slider-runnable-track{cursor:default}.custom-range:disabled::-moz-range-thumb{background-color:#d8dee9}.custom-range:disabled::-moz-range-track{cursor:default}.custom-range:disabled::-ms-thumb{background-color:#d8dee9}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.nav{display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#8c94a4;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #d8dee9}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e5e9f0 #e5e9f0 #d8dee9}.nav-tabs .nav-link.disabled{color:#8c94a4;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#2e3440;background-color:#88c0d0;border-color:#d8dee9 #d8dee9 #88c0d0}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#2e3440;background-color:#88c0d0}.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:.5rem 1rem}.navbar .container,.navbar .container-fluid,.navbar .container-lg,.navbar .container-md,.navbar .container-sm,.navbar .container-xl{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:no-repeat center center;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid,.navbar-expand-sm>.container-lg,.navbar-expand-sm>.container-md,.navbar-expand-sm>.container-sm,.navbar-expand-sm>.container-xl{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid,.navbar-expand-md>.container-lg,.navbar-expand-md>.container-md,.navbar-expand-md>.container-sm,.navbar-expand-md>.container-xl{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:991.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{padding-right:0;padding-left:0}}@media (min-width:992px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid,.navbar-expand-lg>.container-lg,.navbar-expand-lg>.container-md,.navbar-expand-lg>.container-sm,.navbar-expand-lg>.container-xl{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid,.navbar-expand-xl>.container-lg,.navbar-expand-xl>.container-md,.navbar-expand-xl>.container-sm,.navbar-expand-xl>.container-xl{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid,.navbar-expand>.container-lg,.navbar-expand>.container-md,.navbar-expand>.container-sm,.navbar-expand>.container-xl{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand{color:#88c0d0}.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:#eceff4}.navbar-light .navbar-nav .nav-link{color:#eceff4}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:#88c0d0}.navbar-light .navbar-nav .nav-link.disabled{color:#8c94a4}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:#88c0d0}.navbar-light .navbar-toggler{color:#eceff4}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='%23ECEFF4' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#eceff4}.navbar-light .navbar-text a{color:#88c0d0}.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:#88c0d0}.navbar-dark .navbar-brand{color:#2e3440}.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:rgba(76,86,106,.8)}.navbar-dark .navbar-nav .nav-link{color:rgba(76,86,106,.8)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:#2e3440}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(76,86,106,.8)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#2e3440}.navbar-dark .navbar-toggler{color:rgba(76,86,106,.8)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='30' height='30' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2876, 86, 106, 0.8%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:rgba(76,86,106,.8)}.navbar-dark .navbar-text a{color:#2e3440}.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#2e3440}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#3b4252;background-clip:border-box;border:1px solid rgba(46,52,64,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-body{flex:1 1 auto;min-height:1px;padding:1.25rem}.card-title{margin-bottom:.75rem}.card-subtitle{margin-top:-.375rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header{padding:.75rem 1.25rem;margin-bottom:0;background-color:rgba(46,52,64,.03);border-bottom:1px solid rgba(46,52,64,.125)}.card-header:first-child{border-radius:calc(.25rem - 1px) calc(.25rem - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{padding:.75rem 1.25rem;background-color:rgba(46,52,64,.03);border-top:1px solid rgba(46,52,64,.125)}.card-footer:last-child{border-radius:0 0 calc(.25rem - 1px) calc(.25rem - 1px)}.card-header-tabs{margin-right:-.625rem;margin-bottom:-.75rem;margin-left:-.625rem;border-bottom:0}.card-header-pills{margin-right:-.625rem;margin-left:-.625rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img,.card-img-bottom,.card-img-top{flex-shrink:0;width:100%}.card-img,.card-img-top{border-top-left-radius:calc(.25rem - 1px);border-top-right-radius:calc(.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(.25rem - 1px);border-bottom-left-radius:calc(.25rem - 1px)}.card-deck .card{margin-bottom:15px}@media (min-width:576px){.card-deck{display:flex;flex-flow:row wrap;margin-right:-15px;margin-left:-15px}.card-deck .card{flex:1 0 0%;margin-right:15px;margin-bottom:0;margin-left:15px}}.card-group>.card{margin-bottom:15px}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.card-columns .card{margin-bottom:.75rem}@media (min-width:576px){.card-columns{column-count:3;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.accordion>.card{overflow:hidden}.accordion>.card:not(:last-of-type){border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion>.card:not(:first-of-type){border-top-left-radius:0;border-top-right-radius:0}.accordion>.card>.card-header{border-radius:0;margin-bottom:-1px}.breadcrumb{display:flex;flex-wrap:wrap;padding:.75rem 1rem;margin-bottom:1rem;list-style:none;background-color:#3b4252;border-radius:.25rem}.breadcrumb-item{display:flex}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{display:inline-block;padding-right:.5rem;color:#d8dee9;content:"/"}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:underline}.breadcrumb-item+.breadcrumb-item:hover::before{text-decoration:none}.breadcrumb-item.active{color:#88c0d0}.pagination{display:flex;padding-left:0;list-style:none;border-radius:.25rem}.page-link{position:relative;display:block;padding:.5rem .75rem;margin-left:-1px;line-height:1.25;color:#88c0d0;background-color:#3b4252;border:1px solid #3b4252}.page-link:hover{z-index:2;color:#88c0d0;text-decoration:none;background-color:#4c566a;border-color:#88c0d0}.page-link:focus{z-index:3;outline:0;box-shadow:0 0 0 .2rem rgba(136,192,208,.25)}.page-item:first-child .page-link{margin-left:0;border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.page-item.active .page-link{z-index:3;color:#2e3440;background-color:#88c0d0;border-color:#88c0d0}.page-item.disabled .page-link{color:#88c0d0;pointer-events:none;cursor:auto;background-color:#3b4252;border-color:#88c0d0}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem;line-height:1.5}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:.875rem;line-height:1.5}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.25em .4em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}a.badge:focus,a.badge:hover{text-decoration:none}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.badge-pill{padding-right:.6em;padding-left:.6em;border-radius:10rem}.badge-primary{color:#2e3440;background-color:#88c0d0}a.badge-primary:focus,a.badge-primary:hover{color:#2e3440;background-color:#63adc2}a.badge-primary.focus,a.badge-primary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(136,192,208,.5)}.badge-secondary{color:#eceff4;background-color:#4c566a}a.badge-secondary:focus,a.badge-secondary:hover{color:#eceff4;background-color:#373e4c}a.badge-secondary.focus,a.badge-secondary:focus{outline:0;box-shadow:0 0 0 .2rem rgba(76,86,106,.5)}.badge-success{color:#2e3440;background-color:#a3be8c}a.badge-success:focus,a.badge-success:hover{color:#2e3440;background-color:#89ac6b}a.badge-success.focus,a.badge-success:focus{outline:0;box-shadow:0 0 0 .2rem rgba(163,190,140,.5)}.badge-info{color:#2e3440;background-color:#81a1c1}a.badge-info:focus,a.badge-info:hover{color:#2e3440;background-color:#5f88b0}a.badge-info.focus,a.badge-info:focus{outline:0;box-shadow:0 0 0 .2rem rgba(129,161,193,.5)}.badge-warning{color:#2e3440;background-color:#ebcb8b}a.badge-warning:focus,a.badge-warning:hover{color:#2e3440;background-color:#e4b860}a.badge-warning.focus,a.badge-warning:focus{outline:0;box-shadow:0 0 0 .2rem rgba(235,203,139,.5)}.badge-danger{color:#eceff4;background-color:#bf616a}a.badge-danger:focus,a.badge-danger:hover{color:#eceff4;background-color:#a9444e}a.badge-danger.focus,a.badge-danger:focus{outline:0;box-shadow:0 0 0 .2rem rgba(191,97,106,.5)}.badge-light{color:#eceff4;background-color:#3b4252}a.badge-light:focus,a.badge-light:hover{color:#eceff4;background-color:#262a34}a.badge-light.focus,a.badge-light:focus{outline:0;box-shadow:0 0 0 .2rem rgba(59,66,82,.5)}.badge-dark{color:#eceff4;background-color:#8c94a4}a.badge-dark:focus,a.badge-dark:hover{color:#eceff4;background-color:#707a8d}a.badge-dark.focus,a.badge-dark:focus{outline:0;box-shadow:0 0 0 .2rem rgba(140,148,164,.5)}.jumbotron{padding:2rem 1rem;margin-bottom:2rem;background-color:#3b4252;border-radius:.3rem}@media (min-width:576px){.jumbotron{padding:4rem 2rem}}.jumbotron-fluid{padding-right:0;padding-left:0;border-radius:0}.alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:4rem}.alert-dismissible .close{position:absolute;top:0;right:0;padding:.75rem 1.25rem;color:inherit}.alert-primary{color:#d8e6ed;background:#6b93a2 linear-gradient(180deg,#628593,#6b93a2) repeat-x;border-color:#d8e6ed}.alert-primary hr{border-top-color:#c7dbe5}.alert-primary .alert-link{color:#b5d0dd}.alert-secondary{color:#ccd0d8;background:#424b5d linear-gradient(180deg,#3f4859,#424b5d) repeat-x;border-color:#ccd0d8}.alert-secondary hr{border-top-color:#bec3cd}.alert-secondary .alert-link{color:#afb5c2}.alert-success{color:#dde5df;background:#7e9274 linear-gradient(180deg,#72846c,#7e9274) repeat-x;border-color:#dde5df}.alert-success hr{border-top-color:#cfdad1}.alert-success .alert-link{color:#c0cfc4}.alert-info{color:#d7dfea;background:#667e98 linear-gradient(180deg,#5e738b,#667e98) repeat-x;border-color:#d7dfea}.alert-info hr{border-top-color:#c6d2e1}.alert-info .alert-link{color:#b6c4d8}.alert-warning{color:#ece8df;background:#af9b73 linear-gradient(180deg,#9c8c6b,#af9b73) repeat-x;border-color:#ece8df}.alert-warning hr{border-top-color:#e3ddcf}.alert-warning .alert-link{color:#d9d1bf}.alert-danger{color:#e3d3d8;background:#91535d linear-gradient(180deg,#824e59,#91535d) repeat-x;border-color:#e3d3d8}.alert-danger hr{border-top-color:#d9c3ca}.alert-danger .alert-link{color:#cfb4bc}.alert-light{color:#c9ccd4;background:#373e4c linear-gradient(180deg,#363d4a,#373e4c) repeat-x;border-color:#c9ccd4}.alert-light hr{border-top-color:#bbbfc9}.alert-light .alert-link{color:#adb1bd}.alert-dark{color:#d9dde4;background:#6e7584 linear-gradient(180deg,#646b7a,#6e7584) repeat-x;border-color:#d9dde4}.alert-dark hr{border-top-color:#cad0d9}.alert-dark .alert-link{color:#bbc2cf}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{display:flex;height:1rem;overflow:hidden;line-height:0;font-size:.75rem;background-color:#3b4252;border-radius:.25rem;box-shadow:inset 0 .1rem .1rem rgba(46,52,64,.1)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:#3b4252;text-align:center;white-space:nowrap;background-color:#88c0d0;transition:width .6s ease}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(236,239,244,.15) 25%,transparent 25%,transparent 50%,rgba(236,239,244,.15) 50%,rgba(236,239,244,.15) 75%,transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex:1}.list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-item-action{width:100%;color:#d8dee9;text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:#d8dee9;text-decoration:none;background-color:#3b4252}.list-group-item-action:active{color:#88c0d0;background-color:#2e3440}.list-group-item{position:relative;display:block;padding:.75rem 1.25rem;background-color:#3b4252;border:1px solid rgba(46,52,64,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#d8dee9;pointer-events:none;background-color:#3b4252}.list-group-item.active{z-index:2;color:#3b4252;background-color:#88c0d0;border-color:#88c0d0}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{color:#5d7d8b;background-color:#d0e2ea}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#5d7d8b;background-color:#bed7e2}.list-group-item-primary.list-group-item-action.active{color:#eceff4;background-color:#5d7d8b;border-color:#5d7d8b}.list-group-item-secondary{color:#3e4656;background-color:#bfc4cd}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#3e4656;background-color:#b1b7c2}.list-group-item-secondary.list-group-item-action.active{color:#eceff4;background-color:#3e4656;border-color:#3e4656}.list-group-item-success{color:#6b7c68;background-color:#d8e1d7}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#6b7c68;background-color:#cad6c8}.list-group-item-success.list-group-item-action.active{color:#eceff4;background-color:#6b7c68;border-color:#6b7c68}.list-group-item-info{color:#596d83;background-color:#ced9e6}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#596d83;background-color:#bdccdd}.list-group-item-info.list-group-item-action.active{color:#eceff4;background-color:#596d83;border-color:#596d83}.list-group-item-warning{color:#908367;background-color:#ece5d7}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#908367;background-color:#e4dac6}.list-group-item-warning.list-group-item-action.active{color:#eceff4;background-color:#908367;border-color:#908367}.list-group-item-danger{color:#794b56;background-color:#dfc7cd}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#794b56;background-color:#d6b7bf}.list-group-item-danger.list-group-item-action.active{color:#eceff4;background-color:#794b56;border-color:#794b56}.list-group-item-light{color:#353b49;background-color:#babfc7}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#353b49;background-color:#acb2bc}.list-group-item-light.list-group-item-action.active{color:#eceff4;background-color:#353b49;border-color:#353b49}.list-group-item-dark{color:#5f6674;background-color:#d1d6de}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#5f6674;background-color:#c2c9d3}.list-group-item-dark.list-group-item-action.active{color:#eceff4;background-color:#5f6674;border-color:#5f6674}.close{float:right;font-size:1.5rem;font-weight:700;line-height:1;color:#eceff4;text-shadow:0 1px 0 #eceff4;opacity:.5}@media (max-width:1200px){.close{font-size:calc(1.275rem + .3vw)}}.close:hover{color:#eceff4;text-decoration:none}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{opacity:.75}button.close{padding:0;background-color:transparent;border:0}a.close.disabled{pointer-events:none}.toast{max-width:350px;overflow:hidden;font-size:.875rem;background-color:rgba(236,239,244,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .25rem .75rem rgba(46,52,64,.1);backdrop-filter:blur(10px);opacity:0;border-radius:.25rem}.toast:not(:last-child){margin-bottom:.75rem}.toast.showing{opacity:1}.toast.show{display:block;opacity:1}.toast.hide{display:none}.toast-header{display:flex;align-items:center;padding:.25rem .75rem;color:#4c566a;background-color:rgba(236,239,244,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-body{padding:.75rem}.modal-open{overflow:hidden}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;left:0;z-index:1050;display:none;width:100%;height:100%;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{display:flex;max-height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 1rem);overflow:hidden}.modal-dialog-scrollable .modal-footer,.modal-dialog-scrollable .modal-header{flex-shrink:0}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - 1rem)}.modal-dialog-centered::before{display:block;height:calc(100vh - 1rem);height:min-content;content:""}.modal-dialog-centered.modal-dialog-scrollable{flex-direction:column;justify-content:center;height:100%}.modal-dialog-centered.modal-dialog-scrollable .modal-content{max-height:none}.modal-dialog-centered.modal-dialog-scrollable::before{content:none}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#3b4252;background-clip:padding-box;border:1px solid rgba(46,52,64,.2);border-radius:.3rem;box-shadow:0 .25rem .5rem rgba(46,52,64,.5);outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#2e3440}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;align-items:flex-start;justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #3b4252;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.modal-header .close{padding:1rem 1rem;margin:-1rem -1rem -1rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;padding:1rem}.modal-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:.75rem;border-top:1px solid #3b4252;border-bottom-right-radius:calc(.3rem - 1px);border-bottom-left-radius:calc(.3rem - 1px)}.modal-footer>*{margin:.25rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:50px;height:50px;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{max-height:calc(100% - 3.5rem)}.modal-dialog-scrollable .modal-content{max-height:calc(100vh - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-dialog-centered::before{height:calc(100vh - 3.5rem);height:min-content}.modal-content{box-shadow:0 .5rem 1rem rgba(46,52,64,.5)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[x-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[x-placement^=top] .arrow,.bs-tooltip-top .arrow{bottom:0}.bs-tooltip-auto[x-placement^=top] .arrow::before,.bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#2e3440}.bs-tooltip-auto[x-placement^=right],.bs-tooltip-right{padding:0 .4rem}.bs-tooltip-auto[x-placement^=right] .arrow,.bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=right] .arrow::before,.bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#2e3440}.bs-tooltip-auto[x-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[x-placement^=bottom] .arrow,.bs-tooltip-bottom .arrow{top:0}.bs-tooltip-auto[x-placement^=bottom] .arrow::before,.bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#2e3440}.bs-tooltip-auto[x-placement^=left],.bs-tooltip-left{padding:0 .4rem}.bs-tooltip-auto[x-placement^=left] .arrow,.bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-auto[x-placement^=left] .arrow::before,.bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#2e3440}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#eceff4;text-align:center;background-color:#2e3440;border-radius:.25rem}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;max-width:276px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.875rem;word-wrap:break-word;background-color:#eceff4;background-clip:padding-box;border:1px solid rgba(46,52,64,.2);border-radius:.3rem;box-shadow:0 .25rem .5rem rgba(46,52,64,.2)}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 .3rem}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-auto[x-placement^=top],.bs-popover-top{margin-bottom:.5rem}.bs-popover-auto[x-placement^=top]>.arrow,.bs-popover-top>.arrow{bottom:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=top]>.arrow::before,.bs-popover-top>.arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(46,52,64,.25)}.bs-popover-auto[x-placement^=top]>.arrow::after,.bs-popover-top>.arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#eceff4}.bs-popover-auto[x-placement^=right],.bs-popover-right{margin-left:.5rem}.bs-popover-auto[x-placement^=right]>.arrow,.bs-popover-right>.arrow{left:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=right]>.arrow::before,.bs-popover-right>.arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(46,52,64,.25)}.bs-popover-auto[x-placement^=right]>.arrow::after,.bs-popover-right>.arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#eceff4}.bs-popover-auto[x-placement^=bottom],.bs-popover-bottom{margin-top:.5rem}.bs-popover-auto[x-placement^=bottom]>.arrow,.bs-popover-bottom>.arrow{top:calc(-.5rem - 1px)}.bs-popover-auto[x-placement^=bottom]>.arrow::before,.bs-popover-bottom>.arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(46,52,64,.25)}.bs-popover-auto[x-placement^=bottom]>.arrow::after,.bs-popover-bottom>.arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#eceff4}.bs-popover-auto[x-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #e2e7ee}.bs-popover-auto[x-placement^=left],.bs-popover-left{margin-right:.5rem}.bs-popover-auto[x-placement^=left]>.arrow,.bs-popover-left>.arrow{right:calc(-.5rem - 1px);width:.5rem;height:1rem;margin:.3rem 0}.bs-popover-auto[x-placement^=left]>.arrow::before,.bs-popover-left>.arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(46,52,64,.25)}.bs-popover-auto[x-placement^=left]>.arrow::after,.bs-popover-left>.arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#eceff4}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:1rem;background-color:#e2e7ee;border-bottom:1px solid #d2d9e5;border-top-left-radius:calc(.3rem - 1px);border-top-right-radius:calc(.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:.5rem .75rem;color:#eceff4}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .6s ease-in-out}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-right,.carousel-item-next:not(.carousel-item-left){transform:translateX(100%)}.active.carousel-item-left,.carousel-item-prev:not(.carousel-item-right){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-left,.carousel-fade .carousel-item-prev.carousel-item-right,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-left,.carousel-fade .active.carousel-item-right{z-index:0;opacity:0;transition:opacity 0s .6s}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;color:#eceff4;text-align:center;opacity:.5;transition:opacity .15s ease}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#eceff4;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0;background-image:linear-gradient(90deg,rgba(46,52,64,.25),rgba(46,52,64,.001))}.carousel-control-next{right:0;background-image:linear-gradient(270deg,rgba(46,52,64,.25),rgba(46,52,64,.001))}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:20px;height:20px;background:no-repeat 50%/100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23ECEFF4' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5L4.25 4l2.5-2.5L5.25 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23ECEFF4' width='8' height='8' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5L3.75 4l-2.5 2.5L2.75 8l4-4-4-4z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:15;display:flex;justify-content:center;padding-left:0;margin-right:15%;margin-left:15%;list-style:none}.carousel-indicators li{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#eceff4;background-clip:padding-box;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#eceff4;text-align:center}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;animation:spinner-border .75s linear infinite}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:text-bottom;background-color:currentColor;border-radius:50%;opacity:0;animation:spinner-grow .75s linear infinite}.spinner-grow-sm{width:1rem;height:1rem}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#88c0d0!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#63adc2!important}.bg-secondary{background-color:#4c566a!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#373e4c!important}.bg-success{background-color:#a3be8c!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#89ac6b!important}.bg-info{background-color:#81a1c1!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#5f88b0!important}.bg-warning{background-color:#ebcb8b!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#e4b860!important}.bg-danger{background-color:#bf616a!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#a9444e!important}.bg-light{background-color:#3b4252!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#262a34!important}.bg-dark{background-color:#8c94a4!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#707a8d!important}.bg-gradient-primary{background:#88c0d0 linear-gradient(180deg,#7babba,#88c0d0) repeat-x!important}.bg-gradient-secondary{background:#4c566a linear-gradient(180deg,#485164,#4c566a) repeat-x!important}.bg-gradient-success{background:#a3be8c linear-gradient(180deg,#91a981,#a3be8c) repeat-x!important}.bg-gradient-info{background:#81a1c1 linear-gradient(180deg,#7591ae,#81a1c1) repeat-x!important}.bg-gradient-warning{background:#ebcb8b linear-gradient(180deg,#cfb480,#ebcb8b) repeat-x!important}.bg-gradient-danger{background:#bf616a linear-gradient(180deg,#a95a64,#bf616a) repeat-x!important}.bg-gradient-light{background:#3b4252 linear-gradient(180deg,#39404f,#3b4252) repeat-x!important}.bg-gradient-dark{background:#8c94a4 linear-gradient(180deg,#7e8695,#8c94a4) repeat-x!important}.bg-white{background-color:#eceff4!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #d8dee9!important}.border-top{border-top:1px solid #d8dee9!important}.border-right{border-right:1px solid #d8dee9!important}.border-bottom{border-bottom:1px solid #d8dee9!important}.border-left{border-left:1px solid #d8dee9!important}.border-0{border:0!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#88c0d0!important}.border-secondary{border-color:#4c566a!important}.border-success{border-color:#a3be8c!important}.border-info{border-color:#81a1c1!important}.border-warning{border-color:#ebcb8b!important}.border-danger{border-color:#bf616a!important}.border-light{border-color:#3b4252!important}.border-dark{border-color:#8c94a4!important}.border-white{border-color:#eceff4!important}.rounded-sm{border-radius:.2rem!important}.rounded{border-radius:.25rem!important}.rounded-top{border-top-left-radius:.25rem!important;border-top-right-radius:.25rem!important}.rounded-right{border-top-right-radius:.25rem!important;border-bottom-right-radius:.25rem!important}.rounded-bottom{border-bottom-right-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-left{border-top-left-radius:.25rem!important;border-bottom-left-radius:.25rem!important}.rounded-lg{border-radius:.3rem!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-0{border-radius:0!important}.clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media (min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.embed-responsive{position:relative;display:block;width:100%;padding:0;overflow:hidden}.embed-responsive::before{display:block;content:""}.embed-responsive .embed-responsive-item,.embed-responsive embed,.embed-responsive iframe,.embed-responsive object,.embed-responsive video{position:absolute;top:0;bottom:0;left:0;width:100%;height:100%;border:0}.embed-responsive-21by9::before{padding-top:42.85714%}.embed-responsive-16by9::before{padding-top:56.25%}.embed-responsive-4by3::before{padding-top:75%}.embed-responsive-1by1::before{padding-top:100%}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media (min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media (min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media (min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media (min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}@media (min-width:576px){.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}}@media (min-width:768px){.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}}@media (min-width:992px){.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}}@media (min-width:1200px){.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}}.user-select-all{user-select:all!important}.user-select-auto{user-select:auto!important}.user-select-none{user-select:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.sr-only-focusable:active,.sr-only-focusable:focus{position:static;width:auto;height:auto;overflow:visible;clip:auto;white-space:normal}.shadow-sm{box-shadow:0 .125rem .25rem rgba(46,52,64,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(46,52,64,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(46,52,64,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.min-vw-100{min-width:100vw!important}.min-vh-100{min-height:100vh!important}.vw-100{width:100vw!important}.vh-100{height:100vh!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-n1{margin:-.25rem!important}.mt-n1,.my-n1{margin-top:-.25rem!important}.mr-n1,.mx-n1{margin-right:-.25rem!important}.mb-n1,.my-n1{margin-bottom:-.25rem!important}.ml-n1,.mx-n1{margin-left:-.25rem!important}.m-n2{margin:-.5rem!important}.mt-n2,.my-n2{margin-top:-.5rem!important}.mr-n2,.mx-n2{margin-right:-.5rem!important}.mb-n2,.my-n2{margin-bottom:-.5rem!important}.ml-n2,.mx-n2{margin-left:-.5rem!important}.m-n3{margin:-1rem!important}.mt-n3,.my-n3{margin-top:-1rem!important}.mr-n3,.mx-n3{margin-right:-1rem!important}.mb-n3,.my-n3{margin-bottom:-1rem!important}.ml-n3,.mx-n3{margin-left:-1rem!important}.m-n4{margin:-1.5rem!important}.mt-n4,.my-n4{margin-top:-1.5rem!important}.mr-n4,.mx-n4{margin-right:-1.5rem!important}.mb-n4,.my-n4{margin-bottom:-1.5rem!important}.ml-n4,.mx-n4{margin-left:-1.5rem!important}.m-n5{margin:-3rem!important}.mt-n5,.my-n5{margin-top:-3rem!important}.mr-n5,.mx-n5{margin-right:-3rem!important}.mb-n5,.my-n5{margin-bottom:-3rem!important}.ml-n5,.mx-n5{margin-left:-3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}@media (min-width:576px){.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-n1{margin:-.25rem!important}.mt-sm-n1,.my-sm-n1{margin-top:-.25rem!important}.mr-sm-n1,.mx-sm-n1{margin-right:-.25rem!important}.mb-sm-n1,.my-sm-n1{margin-bottom:-.25rem!important}.ml-sm-n1,.mx-sm-n1{margin-left:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.mt-sm-n2,.my-sm-n2{margin-top:-.5rem!important}.mr-sm-n2,.mx-sm-n2{margin-right:-.5rem!important}.mb-sm-n2,.my-sm-n2{margin-bottom:-.5rem!important}.ml-sm-n2,.mx-sm-n2{margin-left:-.5rem!important}.m-sm-n3{margin:-1rem!important}.mt-sm-n3,.my-sm-n3{margin-top:-1rem!important}.mr-sm-n3,.mx-sm-n3{margin-right:-1rem!important}.mb-sm-n3,.my-sm-n3{margin-bottom:-1rem!important}.ml-sm-n3,.mx-sm-n3{margin-left:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.mt-sm-n4,.my-sm-n4{margin-top:-1.5rem!important}.mr-sm-n4,.mx-sm-n4{margin-right:-1.5rem!important}.mb-sm-n4,.my-sm-n4{margin-bottom:-1.5rem!important}.ml-sm-n4,.mx-sm-n4{margin-left:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.mt-sm-n5,.my-sm-n5{margin-top:-3rem!important}.mr-sm-n5,.mx-sm-n5{margin-right:-3rem!important}.mb-sm-n5,.my-sm-n5{margin-bottom:-3rem!important}.ml-sm-n5,.mx-sm-n5{margin-left:-3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}}@media (min-width:768px){.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-n1{margin:-.25rem!important}.mt-md-n1,.my-md-n1{margin-top:-.25rem!important}.mr-md-n1,.mx-md-n1{margin-right:-.25rem!important}.mb-md-n1,.my-md-n1{margin-bottom:-.25rem!important}.ml-md-n1,.mx-md-n1{margin-left:-.25rem!important}.m-md-n2{margin:-.5rem!important}.mt-md-n2,.my-md-n2{margin-top:-.5rem!important}.mr-md-n2,.mx-md-n2{margin-right:-.5rem!important}.mb-md-n2,.my-md-n2{margin-bottom:-.5rem!important}.ml-md-n2,.mx-md-n2{margin-left:-.5rem!important}.m-md-n3{margin:-1rem!important}.mt-md-n3,.my-md-n3{margin-top:-1rem!important}.mr-md-n3,.mx-md-n3{margin-right:-1rem!important}.mb-md-n3,.my-md-n3{margin-bottom:-1rem!important}.ml-md-n3,.mx-md-n3{margin-left:-1rem!important}.m-md-n4{margin:-1.5rem!important}.mt-md-n4,.my-md-n4{margin-top:-1.5rem!important}.mr-md-n4,.mx-md-n4{margin-right:-1.5rem!important}.mb-md-n4,.my-md-n4{margin-bottom:-1.5rem!important}.ml-md-n4,.mx-md-n4{margin-left:-1.5rem!important}.m-md-n5{margin:-3rem!important}.mt-md-n5,.my-md-n5{margin-top:-3rem!important}.mr-md-n5,.mx-md-n5{margin-right:-3rem!important}.mb-md-n5,.my-md-n5{margin-bottom:-3rem!important}.ml-md-n5,.mx-md-n5{margin-left:-3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}}@media (min-width:992px){.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-n1{margin:-.25rem!important}.mt-lg-n1,.my-lg-n1{margin-top:-.25rem!important}.mr-lg-n1,.mx-lg-n1{margin-right:-.25rem!important}.mb-lg-n1,.my-lg-n1{margin-bottom:-.25rem!important}.ml-lg-n1,.mx-lg-n1{margin-left:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.mt-lg-n2,.my-lg-n2{margin-top:-.5rem!important}.mr-lg-n2,.mx-lg-n2{margin-right:-.5rem!important}.mb-lg-n2,.my-lg-n2{margin-bottom:-.5rem!important}.ml-lg-n2,.mx-lg-n2{margin-left:-.5rem!important}.m-lg-n3{margin:-1rem!important}.mt-lg-n3,.my-lg-n3{margin-top:-1rem!important}.mr-lg-n3,.mx-lg-n3{margin-right:-1rem!important}.mb-lg-n3,.my-lg-n3{margin-bottom:-1rem!important}.ml-lg-n3,.mx-lg-n3{margin-left:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.mt-lg-n4,.my-lg-n4{margin-top:-1.5rem!important}.mr-lg-n4,.mx-lg-n4{margin-right:-1.5rem!important}.mb-lg-n4,.my-lg-n4{margin-bottom:-1.5rem!important}.ml-lg-n4,.mx-lg-n4{margin-left:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.mt-lg-n5,.my-lg-n5{margin-top:-3rem!important}.mr-lg-n5,.mx-lg-n5{margin-right:-3rem!important}.mb-lg-n5,.my-lg-n5{margin-bottom:-3rem!important}.ml-lg-n5,.mx-lg-n5{margin-left:-3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}}@media (min-width:1200px){.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-n1{margin:-.25rem!important}.mt-xl-n1,.my-xl-n1{margin-top:-.25rem!important}.mr-xl-n1,.mx-xl-n1{margin-right:-.25rem!important}.mb-xl-n1,.my-xl-n1{margin-bottom:-.25rem!important}.ml-xl-n1,.mx-xl-n1{margin-left:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.mt-xl-n2,.my-xl-n2{margin-top:-.5rem!important}.mr-xl-n2,.mx-xl-n2{margin-right:-.5rem!important}.mb-xl-n2,.my-xl-n2{margin-bottom:-.5rem!important}.ml-xl-n2,.mx-xl-n2{margin-left:-.5rem!important}.m-xl-n3{margin:-1rem!important}.mt-xl-n3,.my-xl-n3{margin-top:-1rem!important}.mr-xl-n3,.mx-xl-n3{margin-right:-1rem!important}.mb-xl-n3,.my-xl-n3{margin-bottom:-1rem!important}.ml-xl-n3,.mx-xl-n3{margin-left:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.mt-xl-n4,.my-xl-n4{margin-top:-1.5rem!important}.mr-xl-n4,.mx-xl-n4{margin-right:-1.5rem!important}.mb-xl-n4,.my-xl-n4{margin-bottom:-1.5rem!important}.ml-xl-n4,.mx-xl-n4{margin-left:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.mt-xl-n5,.my-xl-n5{margin-top:-3rem!important}.mr-xl-n5,.mx-xl-n5{margin-right:-3rem!important}.mb-xl-n5,.my-xl-n5{margin-bottom:-3rem!important}.ml-xl-n5,.mx-xl-n5{margin-left:-3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:auto;content:"";background-color:rgba(0,0,0,0)}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-weight-bolder{font-weight:bolder!important}.font-italic{font-style:italic!important}.text-white{color:#eceff4!important}.text-primary{color:#88c0d0!important}a.text-primary:focus,a.text-primary:hover{color:#51a3ba!important}.text-secondary{color:#4c566a!important}a.text-secondary:focus,a.text-secondary:hover{color:#2c323d!important}.text-success{color:#a3be8c!important}a.text-success:focus,a.text-success:hover{color:#7ca25c!important}.text-info{color:#81a1c1!important}a.text-info:focus,a.text-info:hover{color:#517ba5!important}.text-warning{color:#ebcb8b!important}a.text-warning:focus,a.text-warning:hover{color:#e0ae4a!important}.text-danger{color:#bf616a!important}a.text-danger:focus,a.text-danger:hover{color:#973d46!important}.text-light{color:#3b4252!important}a.text-light:focus,a.text-light:hover{color:#1b1e26!important}.text-dark{color:#8c94a4!important}a.text-dark:focus,a.text-dark:hover{color:#646d7f!important}.text-body{color:#eceff4!important}.text-muted{color:#8c94a4!important}.text-black-50{color:rgba(46,52,64,.5)!important}.text-white-50{color:rgba(236,239,244,.5)!important}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.text-decoration-none{text-decoration:none!important}.text-break{word-wrap:break-word!important}.text-reset{color:inherit!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #d8dee9;page-break-inside:avoid}thead{display:table-header-group}img,tr{page-break-inside:avoid}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}@page{size:a3}body{min-width:992px!important}.container{min-width:992px!important}.navbar{display:none}.badge{border:1px solid #2e3440}.table{border-collapse:collapse!important}.table td,.table th{background-color:#eceff4!important}.table-bordered td,.table-bordered th{border:1px solid #d8dee9!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#d8dee9}.table .thead-dark th{color:inherit;border-color:#d8dee9}}
index d5773b4455a29827a734eed34dc2063bb96ed8ca..3838dca74eb21d56934f1584a3cb3a59e9e9164d 100644 (file)
@@ -1,14 +1,15 @@
 import { hydrate } from "inferno-hydrate";
 import { BrowserRouter } from "inferno-router";
+import { GetSiteResponse } from "lemmy-js-client";
 import { App } from "../shared/components/app/app";
-import { initializeSite } from "../shared/utils";
+import { convertWindowJson, initializeSite } from "../shared/utils";
 
-const site = window.isoData.site_res;
+const site = convertWindowJson(GetSiteResponse, window.isoData.site_res);
 initializeSite(site);
 
 const wrapper = (
   <BrowserRouter>
-    <App siteRes={window.isoData.site_res} />
+    <App />
   </BrowserRouter>
 );
 
index c95e44af29c8ea2aabddea3ef2ffd4cbeb894419..fbac4ee1ac72e67d92d70add2b08a5251ddf7612 100644 (file)
@@ -1,10 +1,13 @@
+import { None, Option } from "@sniptt/monads";
+import { serialize as serializeO } from "class-transformer";
 import express from "express";
+import fs from "fs";
 import { IncomingHttpHeaders } from "http";
 import { Helmet } from "inferno-helmet";
 import { matchPath, StaticRouter } from "inferno-router";
 import { renderToString } from "inferno-server";
 import IsomorphicCookie from "isomorphic-cookie";
-import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
+import { GetSite, GetSiteResponse, LemmyHttp, toOption } from "lemmy-js-client";
 import path from "path";
 import process from "process";
 import serialize from "serialize-javascript";
@@ -17,104 +20,189 @@ import {
   IsoData,
 } from "../shared/interfaces";
 import { routes } from "../shared/routes";
-import { initializeSite, setOptionalAuth } from "../shared/utils";
+import { initializeSite } from "../shared/utils";
 
 const server = express();
 const [hostname, port] = process.env["LEMMY_UI_HOST"]
   ? process.env["LEMMY_UI_HOST"].split(":")
   : ["0.0.0.0", "1234"];
+const extraThemesFolder =
+  process.env["LEMMY_UI_EXTRA_THEMES_FOLDER"] || "./extra_themes";
+
+if (!process.env["LEMMY_UI_DISABLE_CSP"] && !process.env["LEMMY_UI_DEBUG"]) {
+  server.use(function (_req, res, next) {
+    res.setHeader(
+      "Content-Security-Policy",
+      `default-src 'none'; connect-src *; img-src * data:; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; form-action 'self'; base-uri 'self'`
+    );
+    next();
+  });
+}
+const customHtmlHeader = process.env["LEMMY_UI_CUSTOM_HTML_HEADER"] || "";
 
 server.use(express.json());
 server.use(express.urlencoded({ extended: false }));
 server.use("/static", express.static(path.resolve("./dist")));
 
-// server.use(cookieParser());
-
-server.get("/*", async (req, res) => {
-  const activeRoute = routes.find(route => matchPath(req.path, route)) || {};
-  const context = {} as any;
-  let auth: string = IsomorphicCookie.load("jwt", req);
-
-  let getSiteForm: GetSite = {};
-  setOptionalAuth(getSiteForm, auth);
-
-  let promises: Promise<any>[] = [];
-
-  let headers = setForwardedHeaders(req.headers);
-
-  let initialFetchReq: InitialFetchRequest = {
-    client: new LemmyHttp(httpBaseInternal, headers),
-    auth,
-    path: req.path,
-  };
-
-  // Get site data first
-  // This bypasses errors, so that the client can hit the error on its own,
-  // in order to remove the jwt on the browser. Necessary for wrong jwts
-  let try_site: any = await initialFetchReq.client.getSite(getSiteForm);
-  if (try_site.error == "not_logged_in") {
-    console.error(
-      "Incorrect JWT token, skipping auth so frontend can remove jwt cookie"
-    );
-    delete getSiteForm.auth;
-    delete initialFetchReq.auth;
-    try_site = await initialFetchReq.client.getSite(getSiteForm);
-  }
-  let site: GetSiteResponse = try_site;
-  initializeSite(site);
+const robotstxt = `User-Agent: *
+Disallow: /login
+Disallow: /settings
+Disallow: /create_community
+Disallow: /create_post
+Disallow: /create_private_message
+Disallow: /inbox
+Disallow: /setup
+Disallow: /admin
+Disallow: /password_change
+Disallow: /search/
+`;
+
+server.get("/robots.txt", async (_req, res) => {
+  res.setHeader("content-type", "text/plain; charset=utf-8");
+  res.send(robotstxt);
+});
 
-  if (activeRoute.fetchInitialData) {
-    promises.push(...activeRoute.fetchInitialData(initialFetchReq));
+server.get("/css/themes/:name", async (req, res) => {
+  res.contentType("text/css");
+  const theme = req.params.name;
+  if (!theme.endsWith(".css")) {
+    res.send("Theme must be a css file");
   }
 
-  let routeData = await Promise.all(promises);
-
-  // Redirect to the 404 if there's an API error
-  if (routeData[0] && routeData[0].error) {
-    let errCode = routeData[0].error;
-    return res.redirect(`/404?err=${errCode}`);
+  const customTheme = path.resolve(`./${extraThemesFolder}/${theme}`);
+  if (fs.existsSync(customTheme)) {
+    res.sendFile(customTheme);
+  } else {
+    const internalTheme = path.resolve(`./dist/assets/css/themes/${theme}`);
+    res.sendFile(internalTheme);
   }
+});
 
-  let isoData: IsoData = {
-    path: req.path,
-    site_res: site,
-    routeData,
-  };
-
-  const wrapper = (
-    <StaticRouter location={req.url} context={isoData}>
-      <App siteRes={isoData.site_res} />
-    </StaticRouter>
-  );
-  if (context.url) {
-    return res.redirect(context.url);
+function buildThemeList(): string[] {
+  let themes = [
+    "litera",
+    "materia",
+    "minty",
+    "solar",
+    "united",
+    "cyborg",
+    "darkly",
+    "darkly-red",
+    "journal",
+    "sketchy",
+    "vaporwave",
+    "vaporwave-dark",
+    "i386",
+    "litely",
+    "litely-red",
+    "nord",
+  ];
+  if (fs.existsSync(extraThemesFolder)) {
+    let dirThemes = fs.readdirSync(extraThemesFolder);
+    let cssThemes = dirThemes
+      .filter(d => d.endsWith(".css"))
+      .map(d => d.replace(".css", ""));
+    themes.push(...cssThemes);
   }
+  return themes;
+}
 
-  const cspHtml = (
-    <meta
-      http-equiv="Content-Security-Policy"
-      content="default-src data: 'self'; connect-src * ws: wss:; frame-src *; img-src * data:; script-src 'self'; style-src 'self' 'unsafe-inline'; manifest-src 'self'"
-    />
-  );
+server.get("/css/themelist", async (_req, res) => {
+  res.type("json");
+  res.send(JSON.stringify(buildThemeList()));
+});
 
-  const root = renderToString(wrapper);
-  const symbols = renderToString(SYMBOLS);
-  const cspStr = process.env.LEMMY_EXTERNAL_HOST ? renderToString(cspHtml) : "";
-  const helmet = Helmet.renderStatic();
+// server.use(cookieParser());
+server.get("/*", async (req, res) => {
+  try {
+    const activeRoute = routes.find(route => matchPath(req.path, route)) || {};
+    const context = {} as any;
+    let auth: Option<string> = toOption(IsomorphicCookie.load("jwt", req));
+
+    let getSiteForm = new GetSite({ auth });
+
+    let promises: Promise<any>[] = [];
+
+    let headers = setForwardedHeaders(req.headers);
+
+    let initialFetchReq: InitialFetchRequest = {
+      client: new LemmyHttp(httpBaseInternal, headers),
+      auth,
+      path: req.path,
+    };
+
+    // Get site data first
+    // This bypasses errors, so that the client can hit the error on its own,
+    // in order to remove the jwt on the browser. Necessary for wrong jwts
+    let try_site: any = await initialFetchReq.client.getSite(getSiteForm);
+    if (try_site.error == "not_logged_in") {
+      console.error(
+        "Incorrect JWT token, skipping auth so frontend can remove jwt cookie"
+      );
+      getSiteForm.auth = None;
+      initialFetchReq.auth = None;
+      try_site = await initialFetchReq.client.getSite(getSiteForm);
+    }
+    let site: GetSiteResponse = try_site;
+    initializeSite(site);
+
+    if (activeRoute.fetchInitialData) {
+      promises.push(...activeRoute.fetchInitialData(initialFetchReq));
+    }
+
+    let routeData = await Promise.all(promises);
+
+    // Redirect to the 404 if there's an API error
+    if (routeData[0] && routeData[0].error) {
+      let errCode = routeData[0].error;
+      console.error(errCode);
+      if (errCode == "instance_is_private") {
+        return res.redirect(`/signup`);
+      } else {
+        return res.send(`404: ${removeAuthParam(errCode)}`);
+      }
+    }
+
+    let isoData: IsoData = {
+      path: req.path,
+      site_res: site,
+      routeData,
+    };
+
+    const wrapper = (
+      <StaticRouter location={req.url} context={isoData}>
+        <App />
+      </StaticRouter>
+    );
+    if (context.url) {
+      return res.redirect(context.url);
+    }
+
+    const eruda = (
+      <>
+        <script src="//cdn.jsdelivr.net/npm/eruda"></script>
+        <script>eruda.init();</script>
+      </>
+    );
+    const erudaStr = process.env["LEMMY_UI_DEBUG"] ? renderToString(eruda) : "";
+    const root = renderToString(wrapper);
+    const symbols = renderToString(SYMBOLS);
+    const helmet = Helmet.renderStatic();
 
-  const config: ILemmyConfig = { wsHost: process.env.LEMMY_WS_HOST };
+    const config: ILemmyConfig = { wsHost: process.env.LEMMY_UI_LEMMY_WS_HOST };
 
-  res.send(`
+    res.send(`
            <!DOCTYPE html>
            <html ${helmet.htmlAttributes.toString()} lang="en">
            <head>
-           <script>window.isoData = ${serialize(isoData)}</script>
+           <script>window.isoData = ${serializeO(isoData)}</script>
            <script>window.lemmyConfig = ${serialize(config)}</script>
 
-           <!-- A remote debugging utility for mobile
-           <script src="//cdn.jsdelivr.net/npm/eruda"></script>
-           <script>eruda.init();</script>
-           -->
+           <!-- A remote debugging utility for mobile -->
+           ${erudaStr}
+
+           <!-- Custom injected script -->
+           ${customHtmlHeader}
 
            ${helmet.title.toString()}
            ${helmet.meta.toString()}
@@ -124,9 +212,6 @@ server.get("/*", async (req, res) => {
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
 
-           <!-- Content Security Policy -->
-           ${cspStr}
-
            <!-- Web app manifest -->
            <link rel="manifest" href="/static/assets/manifest.webmanifest">
 
@@ -153,6 +238,10 @@ server.get("/*", async (req, res) => {
            </body>
          </html>
 `);
+  } catch (err) {
+    console.error(err);
+    return res.send(`404: ${removeAuthParam(err)}`);
+  }
 });
 
 server.listen(Number(port), hostname, () => {
@@ -179,3 +268,13 @@ process.on("SIGINT", () => {
   console.info("Interrupted");
   process.exit(0);
 });
+
+function removeAuthParam(err: any): string {
+  return removeParam(err.toString(), "auth");
+}
+
+function removeParam(url: string, parameter: string): string {
+  return url
+    .replace(new RegExp("[?&]" + parameter + "=[^&#]*(#.*)?$"), "$1")
+    .replace(new RegExp("([?&])" + parameter + "=[^&]*&"), "$1");
+}
index ddf466b6d6926dbe0ead99906828b83489c98c98..72119a8d601cc9d7f6f21aa98b7e6f933d09e487 100644 (file)
@@ -1,51 +1,47 @@
 import { Component } from "inferno";
 import { Helmet } from "inferno-helmet";
-import { Provider } from "inferno-i18next";
+import { Provider } from "inferno-i18next-dess";
 import { Route, Switch } from "inferno-router";
-import { GetSiteResponse } from "lemmy-js-client";
 import { i18n } from "../../i18next";
 import { routes } from "../../routes";
-import { favIconPngUrl, favIconUrl } from "../../utils";
+import { favIconPngUrl, favIconUrl, setIsoData } from "../../utils";
 import { Footer } from "./footer";
 import { Navbar } from "./navbar";
 import { NoMatch } from "./no-match";
 import "./styles.scss";
 import { Theme } from "./theme";
 
-export interface AppProps {
-  siteRes: GetSiteResponse;
-}
-
-export class App extends Component<AppProps, any> {
+export class App extends Component<any, any> {
+  private isoData = setIsoData(this.context);
   constructor(props: any, context: any) {
     super(props, context);
   }
   render() {
-    let siteRes = this.props.siteRes;
+    let siteRes = this.isoData.site_res;
+    let siteView = siteRes.site_view;
+
     return (
       <>
         <Provider i18next={i18n}>
           <div>
-            <Theme myUserInfo={siteRes.my_user} />
-            {siteRes &&
-              siteRes.site_view &&
-              this.props.siteRes.site_view.site.icon && (
-                <Helmet>
-                  <link
-                    id="favicon"
-                    rel="shortcut icon"
-                    type="image/x-icon"
-                    href={this.props.siteRes.site_view.site.icon || favIconUrl}
-                  />
-                  <link
-                    rel="apple-touch-icon"
-                    href={
-                      this.props.siteRes.site_view.site.icon || favIconPngUrl
-                    }
-                  />
-                </Helmet>
-              )}
-            <Navbar site_res={this.props.siteRes} />
+            <Theme defaultTheme={siteView.map(s => s.site.default_theme)} />
+            {siteView
+              .andThen(s => s.site.icon)
+              .match({
+                some: icon => (
+                  <Helmet>
+                    <link
+                      id="favicon"
+                      rel="shortcut icon"
+                      type="image/x-icon"
+                      href={icon || favIconUrl}
+                    />
+                    <link rel="apple-touch-icon" href={icon || favIconPngUrl} />
+                  </Helmet>
+                ),
+                none: <></>,
+              })}
+            <Navbar siteRes={siteRes} />
             <div class="mt-4 p-0 fl-1">
               <Switch>
                 {routes.map(({ path, exact, component: C, ...rest }) => (
@@ -59,7 +55,7 @@ export class App extends Component<AppProps, any> {
                 <Route render={props => <NoMatch {...props} />} />
               </Switch>
             </div>
-            <Footer site={this.props.siteRes} />
+            <Footer site={siteRes} />
           </div>
         </Provider>
       </>
index de70ac5c821f2ca8753957e0f38ef564df3c2cf7..e5e1db5a5b0a59eb08ecd08ac818506cd9b42885 100644 (file)
@@ -1,5 +1,5 @@
 import { Component } from "inferno";
-import { Link } from "inferno-router";
+import { NavLink } from "inferno-router";
 import { GetSiteResponse } from "lemmy-js-client";
 import { i18n } from "../../i18next";
 import { docsUrl, joinLemmyUrl, repoUrl } from "../../utils";
@@ -28,15 +28,24 @@ export class Footer extends Component<FooterProps, any> {
               <span class="nav-link">BE: {this.props.site.version}</span>
             </li>
             <li className="nav-item">
-              <Link className="nav-link" to="/modlog">
+              <NavLink className="nav-link" to="/modlog">
                 {i18n.t("modlog")}
-              </Link>
+              </NavLink>
             </li>
+            {this.props.site.site_view
+              .andThen(s => s.site.legal_information)
+              .isSome() && (
+              <li className="nav-item">
+                <NavLink className="nav-link" to="/legal">
+                  {i18n.t("legal_information")}
+                </NavLink>
+              </li>
+            )}
             {this.props.site.federated_instances && (
               <li class="nav-item">
-                <Link className="nav-link" to="/instances">
+                <NavLink className="nav-link" to="/instances">
                   {i18n.t("instances")}
-                </Link>
+                </NavLink>
               </li>
             )}
             <li class="nav-item">
index 06304a8c53e45dee8f3ee21955e3e74fa342c628..2408a76b84306fa76476d4e4a023090831bcafeb 100644 (file)
@@ -1,53 +1,48 @@
+import { None, Some } from "@sniptt/monads";
 import { Component, createRef, linkEvent, RefObject } from "inferno";
-import { Link } from "inferno-router";
+import { NavLink } from "inferno-router";
 import {
   CommentResponse,
-  CommentView,
-  GetPersonMentions,
-  GetPersonMentionsResponse,
-  GetPrivateMessages,
-  GetReplies,
-  GetRepliesResponse,
+  GetReportCount,
+  GetReportCountResponse,
   GetSiteResponse,
+  GetUnreadCount,
+  GetUnreadCountResponse,
+  GetUnreadRegistrationApplicationCount,
+  GetUnreadRegistrationApplicationCountResponse,
   PrivateMessageResponse,
-  PrivateMessagesResponse,
-  PrivateMessageView,
-  SortType,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
-  fetchLimit,
-  getLanguage,
+  amAdmin,
+  auth,
+  donateLemmyUrl,
   isBrowser,
   notifyComment,
   notifyPrivateMessage,
-  setTheme,
+  numToSI,
   showAvatars,
-  supportLemmyUrl,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { Icon } from "../common/icon";
 import { PictrsImage } from "../common/pictrs-image";
 
 interface NavbarProps {
-  site_res: GetSiteResponse;
+  siteRes: GetSiteResponse;
 }
 
 interface NavbarState {
-  isLoggedIn: boolean;
   expanded: boolean;
-  replies: CommentView[];
-  mentions: CommentView[];
-  messages: PrivateMessageView[];
-  unreadCount: number;
+  unreadInboxCount: number;
+  unreadReportCount: number;
+  unreadApplicationCount: number;
   searchParam: string;
   toggleSearch: boolean;
   showDropdown: boolean;
@@ -57,14 +52,14 @@ interface NavbarState {
 export class Navbar extends Component<NavbarProps, NavbarState> {
   private wsSub: Subscription;
   private userSub: Subscription;
-  private unreadCountSub: Subscription;
+  private unreadInboxCountSub: Subscription;
+  private unreadReportCountSub: Subscription;
+  private unreadApplicationCountSub: Subscription;
   private searchTextField: RefObject<HTMLInputElement>;
   emptyState: NavbarState = {
-    isLoggedIn: !!this.props.site_res.my_user,
-    unreadCount: 0,
-    replies: [],
-    mentions: [],
-    messages: [],
+    unreadInboxCount: 0,
+    unreadReportCount: 0,
+    unreadApplicationCount: 0,
     expanded: false,
     searchParam: "",
     toggleSearch: false,
@@ -83,51 +78,48 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
   componentDidMount() {
     // Subscribe to jwt changes
     if (isBrowser()) {
-      this.websocketEvents();
-
       this.searchTextField = createRef();
-      console.log(`isLoggedIn = ${this.state.isLoggedIn}`);
 
       // On the first load, check the unreads
-      if (this.state.isLoggedIn == false) {
-        // setTheme(data.my_user.theme, true);
-        // i18n.changeLanguage(getLanguage());
-        // i18n.changeLanguage('de');
-      } else {
+      if (UserService.Instance.myUserInfo.isSome()) {
         this.requestNotificationPermission();
         WebSocketService.Instance.send(
           wsClient.userJoin({
-            auth: authField(),
+            auth: auth().unwrap(),
           })
         );
-        this.fetchUnreads();
-      }
 
-      this.userSub = UserService.Instance.jwtSub.subscribe(res => {
-        // A login
-        if (res !== undefined) {
-          this.requestNotificationPermission();
-          WebSocketService.Instance.send(
-            wsClient.getSite({ auth: authField() })
-          );
-        } else {
-          this.setState({ isLoggedIn: false });
+        if (this.props.siteRes.site_view.isSome()) {
+          this.fetchUnreads();
         }
-      });
+      }
+
+      this.requestNotificationPermission();
 
       // Subscribe to unread count changes
-      this.unreadCountSub = UserService.Instance.unreadCountSub.subscribe(
-        res => {
-          this.setState({ unreadCount: res });
-        }
-      );
+      this.unreadInboxCountSub =
+        UserService.Instance.unreadInboxCountSub.subscribe(res => {
+          this.setState({ unreadInboxCount: res });
+        });
+      // Subscribe to unread report count changes
+      this.unreadReportCountSub =
+        UserService.Instance.unreadReportCountSub.subscribe(res => {
+          this.setState({ unreadReportCount: res });
+        });
+      // Subscribe to unread application count
+      this.unreadApplicationCountSub =
+        UserService.Instance.unreadApplicationCountSub.subscribe(res => {
+          this.setState({ unreadApplicationCount: res });
+        });
     }
   }
 
   componentWillUnmount() {
     this.wsSub.unsubscribe();
     this.userSub.unsubscribe();
-    this.unreadCountSub.unsubscribe();
+    this.unreadInboxCountSub.unsubscribe();
+    this.unreadReportCountSub.unsubscribe();
+    this.unreadApplicationCountSub.unsubscribe();
   }
 
   updateUrl() {
@@ -151,54 +143,102 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
 
   // TODO class active corresponding to current page
   navbar() {
-    let myUserInfo =
-      UserService.Instance.myUserInfo || this.props.site_res.my_user;
-    let person = myUserInfo?.local_user_view.person;
     return (
-      <nav class="navbar navbar-expand-lg navbar-light shadow-sm p-0 px-3">
+      <nav class="navbar navbar-expand-md navbar-light shadow-sm p-0 px-3">
         <div class="container">
-          {this.props.site_res.site_view && (
-            <button
-              title={
-                this.props.site_res.site_view.site.description ||
-                this.props.site_res.site_view.site.name
-              }
-              className="d-flex align-items-center navbar-brand mr-md-3 btn btn-link"
-              onClick={linkEvent(this, this.handleGotoHome)}
-            >
-              {this.props.site_res.site_view.site.icon && showAvatars() && (
-                <PictrsImage
-                  src={this.props.site_res.site_view.site.icon}
-                  icon
-                />
+          {this.props.siteRes.site_view.match({
+            some: siteView => (
+              <NavLink
+                to="/"
+                onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                title={siteView.site.description.unwrapOr(siteView.site.name)}
+                className="d-flex align-items-center navbar-brand mr-md-3"
+              >
+                {siteView.site.icon.match({
+                  some: icon =>
+                    showAvatars() && <PictrsImage src={icon} icon />,
+                  none: <></>,
+                })}
+                {siteView.site.name}
+              </NavLink>
+            ),
+            none: <></>,
+          })}
+          {UserService.Instance.myUserInfo.isSome() && (
+            <>
+              <ul class="navbar-nav ml-auto">
+                <li className="nav-item">
+                  <NavLink
+                    to="/inbox"
+                    className="p-1 navbar-toggler nav-link border-0"
+                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                    title={i18n.t("unread_messages", {
+                      count: this.state.unreadInboxCount,
+                      formattedCount: numToSI(this.state.unreadInboxCount),
+                    })}
+                  >
+                    <Icon icon="bell" />
+                    {this.state.unreadInboxCount > 0 && (
+                      <span class="mx-1 badge badge-light">
+                        {numToSI(this.state.unreadInboxCount)}
+                      </span>
+                    )}
+                  </NavLink>
+                </li>
+              </ul>
+              {this.moderatesSomething && (
+                <ul class="navbar-nav ml-1">
+                  <li className="nav-item">
+                    <NavLink
+                      to="/reports"
+                      className="p-1 navbar-toggler nav-link border-0"
+                      onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                      title={i18n.t("unread_reports", {
+                        count: this.state.unreadReportCount,
+                        formattedCount: numToSI(this.state.unreadReportCount),
+                      })}
+                    >
+                      <Icon icon="shield" />
+                      {this.state.unreadReportCount > 0 && (
+                        <span class="mx-1 badge badge-light">
+                          {numToSI(this.state.unreadReportCount)}
+                        </span>
+                      )}
+                    </NavLink>
+                  </li>
+                </ul>
               )}
-              {this.props.site_res.site_view.site.name}
-            </button>
-          )}
-          {this.state.isLoggedIn && (
-            <button
-              className="ml-auto p-1 navbar-toggler nav-link border-0 btn btn-link"
-              onClick={linkEvent(this, this.handleGotoInbox)}
-              title={i18n.t("inbox")}
-            >
-              <Icon icon="bell" />
-              {this.state.unreadCount > 0 && (
-                <span
-                  class="mx-1 badge badge-light"
-                  aria-label={`${this.state.unreadCount} ${i18n.t(
-                    "unread_messages"
-                  )}`}
-                >
-                  {this.state.unreadCount}
-                </span>
+              {this.amAdmin && (
+                <ul class="navbar-nav ml-1">
+                  <li className="nav-item">
+                    <NavLink
+                      to="/registration_applications"
+                      className="p-1 navbar-toggler nav-link border-0"
+                      onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                      title={i18n.t("unread_registration_applications", {
+                        count: this.state.unreadApplicationCount,
+                        formattedCount: numToSI(
+                          this.state.unreadApplicationCount
+                        ),
+                      })}
+                    >
+                      <Icon icon="clipboard" />
+                      {this.state.unreadApplicationCount > 0 && (
+                        <span class="mx-1 badge badge-light">
+                          {numToSI(this.state.unreadApplicationCount)}
+                        </span>
+                      )}
+                    </NavLink>
+                  </li>
+                </ul>
               )}
-            </button>
+            </>
           )}
           <button
             class="navbar-toggler border-0 p-1"
             type="button"
             aria-label="menu"
-            onClick={linkEvent(this, this.expandNavbar)}
+            onClick={linkEvent(this, this.handleToggleExpandNavbar)}
             data-tippy-content={i18n.t("expand_here")}
           >
             <Icon icon="menu" />
@@ -208,54 +248,61 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
           >
             <ul class="navbar-nav my-2 mr-auto">
               <li class="nav-item">
-                <button
-                  className="nav-link btn btn-link"
-                  onClick={linkEvent(this, this.handleGotoCommunities)}
+                <NavLink
+                  to="/communities"
+                  className="nav-link"
+                  onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                   title={i18n.t("communities")}
                 >
                   {i18n.t("communities")}
-                </button>
+                </NavLink>
               </li>
               <li class="nav-item">
-                <button
-                  className="nav-link btn btn-link"
-                  onClick={linkEvent(this, this.handleGotoCreatePost)}
+                <NavLink
+                  to={{
+                    pathname: "/create_post",
+                    prevPath: this.currentLocation,
+                  }}
+                  className="nav-link"
+                  onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                   title={i18n.t("create_post")}
                 >
                   {i18n.t("create_post")}
-                </button>
+                </NavLink>
               </li>
               {this.canCreateCommunity && (
                 <li class="nav-item">
-                  <button
-                    className="nav-link btn btn-link"
-                    onClick={linkEvent(this, this.handleGotoCreateCommunity)}
+                  <NavLink
+                    to="/create_community"
+                    className="nav-link"
+                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                     title={i18n.t("create_community")}
                   >
                     {i18n.t("create_community")}
-                  </button>
+                  </NavLink>
                 </li>
               )}
               <li class="nav-item">
                 <a
                   className="nav-link"
                   title={i18n.t("support_lemmy")}
-                  href={supportLemmyUrl}
+                  href={donateLemmyUrl}
                 >
                   <Icon icon="heart" classes="small" />
                 </a>
               </li>
             </ul>
             <ul class="navbar-nav my-2">
-              {this.canAdmin && (
+              {this.amAdmin && (
                 <li className="nav-item">
-                  <button
-                    className="nav-link btn btn-link"
-                    onClick={linkEvent(this, this.handleGotoAdmin)}
+                  <NavLink
+                    to="/admin"
+                    className="nav-link"
+                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
                     title={i18n.t("admin_settings")}
                   >
                     <Icon icon="settings" />
-                  </button>
+                  </NavLink>
                 </li>
               )}
             </ul>
@@ -263,7 +310,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
               /^\/search/
             ) && (
               <form
-                class="form-inline"
+                class="form-inline mr-2"
                 onSubmit={linkEvent(this, this.handleSearchSubmit)}
               >
                 <input
@@ -292,97 +339,171 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
                 </button>
               </form>
             )}
-            {this.state.isLoggedIn ? (
+            {UserService.Instance.myUserInfo.isSome() ? (
               <>
                 <ul class="navbar-nav my-2">
                   <li className="nav-item">
-                    <Link
+                    <NavLink
                       className="nav-link"
                       to="/inbox"
-                      title={i18n.t("inbox")}
+                      onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                      title={i18n.t("unread_messages", {
+                        count: this.state.unreadInboxCount,
+                        formattedCount: numToSI(this.state.unreadInboxCount),
+                      })}
                     >
                       <Icon icon="bell" />
-                      {this.state.unreadCount > 0 && (
-                        <span
-                          class="ml-1 badge badge-light"
-                          aria-label={`${this.state.unreadCount} ${i18n.t(
-                            "unread_messages"
-                          )}`}
-                        >
-                          {this.state.unreadCount}
+                      {this.state.unreadInboxCount > 0 && (
+                        <span class="ml-1 badge badge-light">
+                          {numToSI(this.state.unreadInboxCount)}
                         </span>
                       )}
-                    </Link>
+                    </NavLink>
                   </li>
                 </ul>
-                <ul class="navbar-nav">
-                  <li class="nav-item dropdown">
-                    <button
-                      class="nav-link btn btn-link dropdown-toggle"
-                      onClick={linkEvent(this, this.handleShowDropdown)}
-                      id="navbarDropdown"
-                      role="button"
-                      aria-expanded="false"
-                    >
-                      <span>
-                        {person.avatar && showAvatars() && (
-                          <PictrsImage src={person.avatar} icon />
+                {this.moderatesSomething && (
+                  <ul class="navbar-nav my-2">
+                    <li className="nav-item">
+                      <NavLink
+                        className="nav-link"
+                        to="/reports"
+                        onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                        title={i18n.t("unread_reports", {
+                          count: this.state.unreadReportCount,
+                          formattedCount: numToSI(this.state.unreadReportCount),
+                        })}
+                      >
+                        <Icon icon="shield" />
+                        {this.state.unreadReportCount > 0 && (
+                          <span class="ml-1 badge badge-light">
+                            {numToSI(this.state.unreadReportCount)}
+                          </span>
                         )}
-                        {person.display_name
-                          ? person.display_name
-                          : person.name}
-                      </span>
-                    </button>
-                    {this.state.showDropdown && (
-                      <div class="dropdown-content">
-                        <li className="nav-item">
-                          <button
-                            className="nav-link btn btn-link"
-                            onClick={linkEvent(this, this.handleGotoProfile)}
-                            title={i18n.t("profile")}
-                          >
-                            <Icon icon="user" classes="mr-1" />
-                            {i18n.t("profile")}
-                          </button>
-                        </li>
-                        <li className="nav-item">
-                          <button
-                            className="nav-link btn btn-link"
-                            onClick={linkEvent(this, this.handleGotoSettings)}
-                            title={i18n.t("settings")}
-                          >
-                            <Icon icon="settings" classes="mr-1" />
-                            {i18n.t("settings")}
-                          </button>
-                        </li>
-                        <li>
-                          <hr class="dropdown-divider" />
-                        </li>
-                        <li className="nav-item">
+                      </NavLink>
+                    </li>
+                  </ul>
+                )}
+                {this.amAdmin && (
+                  <ul class="navbar-nav my-2">
+                    <li className="nav-item">
+                      <NavLink
+                        to="/registration_applications"
+                        className="nav-link"
+                        onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                        title={i18n.t("unread_registration_applications", {
+                          count: this.state.unreadApplicationCount,
+                          formattedCount: numToSI(
+                            this.state.unreadApplicationCount
+                          ),
+                        })}
+                      >
+                        <Icon icon="clipboard" />
+                        {this.state.unreadApplicationCount > 0 && (
+                          <span class="mx-1 badge badge-light">
+                            {numToSI(this.state.unreadApplicationCount)}
+                          </span>
+                        )}
+                      </NavLink>
+                    </li>
+                  </ul>
+                )}
+                {UserService.Instance.myUserInfo
+                  .map(m => m.local_user_view.person)
+                  .match({
+                    some: person => (
+                      <ul class="navbar-nav">
+                        <li class="nav-item dropdown">
                           <button
-                            className="nav-link btn btn-link"
-                            onClick={linkEvent(this, this.handleLogoutClick)}
-                            title="test"
+                            class="nav-link btn btn-link dropdown-toggle"
+                            onClick={linkEvent(this, this.handleToggleDropdown)}
+                            id="navbarDropdown"
+                            role="button"
+                            aria-expanded="false"
                           >
-                            <Icon icon="log-out" classes="mr-1" />
-                            {i18n.t("logout")}
+                            <span>
+                              {showAvatars() &&
+                                person.avatar.match({
+                                  some: avatar => (
+                                    <PictrsImage src={avatar} icon />
+                                  ),
+                                  none: <></>,
+                                })}
+                              {person.display_name.unwrapOr(person.name)}
+                            </span>
                           </button>
+                          {this.state.showDropdown && (
+                            <div
+                              class="dropdown-content"
+                              onMouseLeave={linkEvent(
+                                this,
+                                this.handleToggleDropdown
+                              )}
+                            >
+                              <li className="nav-item">
+                                <NavLink
+                                  to={`/u/${person.name}`}
+                                  className="nav-link"
+                                  title={i18n.t("profile")}
+                                >
+                                  <Icon icon="user" classes="mr-1" />
+                                  {i18n.t("profile")}
+                                </NavLink>
+                              </li>
+                              <li className="nav-item">
+                                <NavLink
+                                  to="/settings"
+                                  className="nav-link"
+                                  title={i18n.t("settings")}
+                                >
+                                  <Icon icon="settings" classes="mr-1" />
+                                  {i18n.t("settings")}
+                                </NavLink>
+                              </li>
+                              <li>
+                                <hr class="dropdown-divider" />
+                              </li>
+                              <li className="nav-item">
+                                <button
+                                  className="nav-link btn btn-link"
+                                  onClick={linkEvent(
+                                    this,
+                                    this.handleLogoutClick
+                                  )}
+                                  title="test"
+                                >
+                                  <Icon icon="log-out" classes="mr-1" />
+                                  {i18n.t("logout")}
+                                </button>
+                              </li>
+                            </div>
+                          )}
                         </li>
-                      </div>
-                    )}
-                  </li>
-                </ul>
+                      </ul>
+                    ),
+                    none: <></>,
+                  })}
               </>
             ) : (
               <ul class="navbar-nav my-2">
-                <li className="ml-2 nav-item">
-                  <button
-                    className="btn btn-success"
-                    onClick={linkEvent(this, this.handleGotoLogin)}
-                    title={i18n.t("login_sign_up")}
+                <li className="nav-item">
+                  <NavLink
+                    to="/login"
+                    className="nav-link"
+                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                    title={i18n.t("login")}
                   >
-                    {i18n.t("login_sign_up")}
-                  </button>
+                    {i18n.t("login")}
+                  </NavLink>
+                </li>
+                <li className="nav-item">
+                  <NavLink
+                    to="/signup"
+                    className="nav-link"
+                    onMouseUp={linkEvent(this, this.handleHideExpandNavbar)}
+                    title={i18n.t("sign_up")}
+                  >
+                    {i18n.t("sign_up")}
+                  </NavLink>
                 </li>
               </ul>
             )}
@@ -392,11 +513,33 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
     );
   }
 
-  expandNavbar(i: Navbar) {
+  get moderatesSomething(): boolean {
+    return (
+      UserService.Instance.myUserInfo.map(m => m.moderates).unwrapOr([])
+        .length > 0
+    );
+  }
+
+  get amAdmin(): boolean {
+    return amAdmin(Some(this.props.siteRes.admins));
+  }
+
+  get canCreateCommunity(): boolean {
+    let adminOnly = this.props.siteRes.site_view
+      .map(s => s.site.community_creation_admin_only)
+      .unwrapOr(false);
+    return !adminOnly || this.amAdmin;
+  }
+
+  handleToggleExpandNavbar(i: Navbar) {
     i.state.expanded = !i.state.expanded;
     i.setState(i.state);
   }
 
+  handleHideExpandNavbar(i: Navbar) {
+    i.setState({ expanded: false, showDropdown: false });
+  }
+
   handleSearchParam(i: Navbar, event: any) {
     i.state.searchParam = event.target.value;
     i.setState(i.state);
@@ -428,60 +571,9 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
   handleLogoutClick(i: Navbar) {
     i.setState({ showDropdown: false, expanded: false });
     UserService.Instance.logout();
-    i.context.router.history.push("/");
-    location.reload();
   }
 
-  handleGotoSettings(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push("/settings");
-  }
-
-  handleGotoProfile(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(
-      `/u/${UserService.Instance.myUserInfo.local_user_view.person.name}`
-    );
-  }
-
-  handleGotoCreatePost(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push("/create_post", {
-      prevPath: i.currentLocation,
-    });
-  }
-
-  handleGotoCreateCommunity(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(`/create_community`);
-  }
-
-  handleGotoCommunities(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(`/communities`);
-  }
-
-  handleGotoHome(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(`/`);
-  }
-
-  handleGotoInbox(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(`/inbox`);
-  }
-
-  handleGotoAdmin(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(`/admin`);
-  }
-
-  handleGotoLogin(i: Navbar) {
-    i.setState({ showDropdown: false, expanded: false });
-    i.context.router.history.push(`/login`);
-  }
-
-  handleShowDropdown(i: Navbar) {
+  handleToggleDropdown(i: Navbar) {
     i.state.showDropdown = !i.state.showDropdown;
     i.setState(i.state);
   }
@@ -492,120 +584,107 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
     if (msg.error) {
       if (msg.error == "not_logged_in") {
         UserService.Instance.logout();
-        location.reload();
       }
       return;
     } else if (msg.reconnect) {
       console.log(i18n.t("websocket_reconnected"));
-      WebSocketService.Instance.send(
-        wsClient.userJoin({
-          auth: authField(),
-        })
+      if (UserService.Instance.myUserInfo.isSome()) {
+        WebSocketService.Instance.send(
+          wsClient.userJoin({
+            auth: auth().unwrap(),
+          })
+        );
+        this.fetchUnreads();
+      }
+    } else if (op == UserOperation.GetUnreadCount) {
+      let data = wsJsonToRes<GetUnreadCountResponse>(
+        msg,
+        GetUnreadCountResponse
       );
-      this.fetchUnreads();
-    } else if (op == UserOperation.GetReplies) {
-      let data = wsJsonToRes<GetRepliesResponse>(msg).data;
-      let unreadReplies = data.replies.filter(r => !r.comment.read);
-
-      this.state.replies = unreadReplies;
-      this.state.unreadCount = this.calculateUnreadCount();
+      this.state.unreadInboxCount =
+        data.replies + data.mentions + data.private_messages;
       this.setState(this.state);
       this.sendUnreadCount();
-    } else if (op == UserOperation.GetPersonMentions) {
-      let data = wsJsonToRes<GetPersonMentionsResponse>(msg).data;
-      let unreadMentions = data.mentions.filter(r => !r.comment.read);
-
-      this.state.mentions = unreadMentions;
-      this.state.unreadCount = this.calculateUnreadCount();
-      this.setState(this.state);
-      this.sendUnreadCount();
-    } else if (op == UserOperation.GetPrivateMessages) {
-      let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
-      let unreadMessages = data.private_messages.filter(
-        r => !r.private_message.read
+    } else if (op == UserOperation.GetReportCount) {
+      let data = wsJsonToRes<GetReportCountResponse>(
+        msg,
+        GetReportCountResponse
       );
-
-      this.state.messages = unreadMessages;
-      this.state.unreadCount = this.calculateUnreadCount();
+      this.state.unreadReportCount = data.post_reports + data.comment_reports;
       this.setState(this.state);
-      this.sendUnreadCount();
-    } else if (op == UserOperation.GetSite) {
-      // This is only called on a successful login
-      let data = wsJsonToRes<GetSiteResponse>(msg).data;
-      console.log(data.my_user);
-      UserService.Instance.myUserInfo = data.my_user;
-      setTheme(
-        UserService.Instance.myUserInfo.local_user_view.local_user.theme
+      this.sendReportUnread();
+    } else if (op == UserOperation.GetUnreadRegistrationApplicationCount) {
+      let data = wsJsonToRes<GetUnreadRegistrationApplicationCountResponse>(
+        msg,
+        GetUnreadRegistrationApplicationCountResponse
       );
-      i18n.changeLanguage(getLanguage());
-      this.state.isLoggedIn = true;
+      this.state.unreadApplicationCount = data.registration_applications;
       this.setState(this.state);
+      this.sendApplicationUnread();
     } else if (op == UserOperation.CreateComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-
-      if (this.state.isLoggedIn) {
-        if (
-          data.recipient_ids.includes(
-            UserService.Instance.myUserInfo.local_user_view.local_user.id
-          )
-        ) {
-          this.state.replies.push(data.comment_view);
-          this.state.unreadCount++;
-          this.setState(this.state);
-          this.sendUnreadCount();
-          notifyComment(data.comment_view, this.context.router);
-        }
-      }
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          if (data.recipient_ids.includes(mui.local_user_view.local_user.id)) {
+            this.state.unreadInboxCount++;
+            this.setState(this.state);
+            this.sendUnreadCount();
+            notifyComment(data.comment_view, this.context.router);
+          }
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.CreatePrivateMessage) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
-
-      if (this.state.isLoggedIn) {
-        if (
-          data.private_message_view.recipient.id ==
-          UserService.Instance.myUserInfo.local_user_view.person.id
-        ) {
-          this.state.messages.push(data.private_message_view);
-          this.state.unreadCount++;
-          this.setState(this.state);
-          this.sendUnreadCount();
-          notifyPrivateMessage(data.private_message_view, this.context.router);
-        }
-      }
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
+
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          if (
+            data.private_message_view.recipient.id ==
+            mui.local_user_view.person.id
+          ) {
+            this.state.unreadInboxCount++;
+            this.setState(this.state);
+            this.sendUnreadCount();
+            notifyPrivateMessage(
+              data.private_message_view,
+              this.context.router
+            );
+          }
+        },
+        none: void 0,
+      });
     }
   }
 
   fetchUnreads() {
-    console.log("Fetching unreads...");
-    let repliesForm: GetReplies = {
-      sort: SortType.New,
-      unread_only: true,
-      page: 1,
-      limit: fetchLimit,
-      auth: authField(),
-    };
-
-    let personMentionsForm: GetPersonMentions = {
-      sort: SortType.New,
-      unread_only: true,
-      page: 1,
-      limit: fetchLimit,
-      auth: authField(),
-    };
-
-    let privateMessagesForm: GetPrivateMessages = {
-      unread_only: true,
-      page: 1,
-      limit: fetchLimit,
-      auth: authField(),
-    };
-
-    if (this.currentLocation !== "/inbox") {
-      WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
-      WebSocketService.Instance.send(
-        wsClient.getPersonMentions(personMentionsForm)
-      );
+    console.log("Fetching inbox unreads...");
+
+    let unreadForm = new GetUnreadCount({
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.getUnreadCount(unreadForm));
+
+    console.log("Fetching reports...");
+
+    let reportCountForm = new GetReportCount({
+      community_id: None,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.getReportCount(reportCountForm));
+
+    if (this.amAdmin) {
+      console.log("Fetching applications...");
+
+      let applicationCountForm = new GetUnreadRegistrationApplicationCount({
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(
-        wsClient.getPrivateMessages(privateMessagesForm)
+        wsClient.getUnreadRegistrationApplicationCount(applicationCountForm)
       );
     }
   }
@@ -615,42 +694,23 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
   }
 
   sendUnreadCount() {
-    UserService.Instance.unreadCountSub.next(this.state.unreadCount);
+    UserService.Instance.unreadInboxCountSub.next(this.state.unreadInboxCount);
   }
 
-  calculateUnreadCount(): number {
-    return (
-      this.state.replies.filter(r => !r.comment.read).length +
-      this.state.mentions.filter(r => !r.comment.read).length +
-      this.state.messages.filter(r => !r.private_message.read).length
+  sendReportUnread() {
+    UserService.Instance.unreadReportCountSub.next(
+      this.state.unreadReportCount
     );
   }
 
-  get canAdmin(): boolean {
-    return (
-      UserService.Instance.myUserInfo &&
-      this.props.site_res.admins
-        .map(a => a.person.id)
-        .includes(UserService.Instance.myUserInfo.local_user_view.person.id)
+  sendApplicationUnread() {
+    UserService.Instance.unreadApplicationCountSub.next(
+      this.state.unreadApplicationCount
     );
   }
 
-  get canCreateCommunity(): boolean {
-    let adminOnly =
-      this.props.site_res.site_view?.site.community_creation_admin_only;
-    return !adminOnly || this.canAdmin;
-  }
-
-  /// Listens for some websocket errors
-  websocketEvents() {
-    let msg = i18n.t("websocket_disconnected");
-    WebSocketService.Instance.closeEventListener(() => {
-      console.error(msg);
-    });
-  }
-
   requestNotificationPermission() {
-    if (UserService.Instance.myUserInfo) {
+    if (UserService.Instance.myUserInfo.isSome()) {
       document.addEventListener("DOMContentLoaded", function () {
         if (!Notification) {
           toast(i18n.t("notifications_error"), "danger");
index bf5289b127dd9e03b11a2560e7a95b5d92a8d90d..a30358fe9786daa2163f08a3b3fca09f68a541e2 100644 (file)
@@ -1,43 +1,63 @@
+import { Option } from "@sniptt/monads";
 import { Component } from "inferno";
 import { Helmet } from "inferno-helmet";
-import { MyUserInfo } from "lemmy-js-client";
+import { UserService } from "../../services";
 
 interface Props {
-  myUserInfo: MyUserInfo | undefined;
+  defaultTheme: Option<string>;
 }
 
 export class Theme extends Component<Props> {
   render() {
-    let user = this.props.myUserInfo;
-    let hasTheme = user && user.local_user_view.local_user.theme !== "browser";
+    let user = UserService.Instance.myUserInfo;
+    let hasTheme = user
+      .map(m => m.local_user_view.local_user.theme !== "browser")
+      .unwrapOr(false);
 
-    return (
-      <Helmet>
-        {hasTheme ? (
+    if (hasTheme) {
+      return (
+        <Helmet>
           <link
             rel="stylesheet"
             type="text/css"
-            href={`/static/assets/css/themes/${user.local_user_view.local_user.theme}.min.css`}
+            href={`/css/themes/${
+              user.unwrap().local_user_view.local_user.theme
+            }.css`}
           />
-        ) : (
-          [
-            <link
-              rel="stylesheet"
-              type="text/css"
-              href="/static/assets/css/themes/litely.min.css"
-              id="default-light"
-              media="(prefers-color-scheme: light)"
-            />,
-            <link
-              rel="stylesheet"
-              type="text/css"
-              href="/static/assets/css/themes/darkly.min.css"
-              id="default-dark"
-              media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
-            />,
-          ]
-        )}
-      </Helmet>
-    );
+        </Helmet>
+      );
+    } else if (
+      this.props.defaultTheme.isSome() &&
+      this.props.defaultTheme.unwrap() != "browser"
+    ) {
+      return (
+        <Helmet>
+          <link
+            rel="stylesheet"
+            type="text/css"
+            href={`/css/themes/${this.props.defaultTheme.unwrap()}.css`}
+          />
+        </Helmet>
+      );
+    } else {
+      return (
+        <Helmet>
+          <link
+            rel="stylesheet"
+            type="text/css"
+            href="/css/themes/litely.css"
+            id="default-light"
+            media="(prefers-color-scheme: light)"
+          />
+          <link
+            rel="stylesheet"
+            type="text/css"
+            href="/css/themes/darkly.css"
+            id="default-dark"
+            media="(prefers-color-scheme: no-preference), (prefers-color-scheme: dark)"
+          />
+        </Helmet>
+      );
+    }
   }
 }
index 95dff716080238e57665658d385fe8409f479eb4..6778b68fc16fb562a0c3eabedb6d90262c8fb5d5 100644 (file)
@@ -1,30 +1,33 @@
+import { Either, None, Option, Some } from "@sniptt/monads";
 import { Component } from "inferno";
-import { T } from "inferno-i18next";
+import { T } from "inferno-i18next-dess";
 import { Link } from "inferno-router";
 import {
+  CommentNode as CommentNodeI,
   CommentResponse,
   CreateComment,
   EditComment,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
-import { CommentNode as CommentNodeI } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { Icon } from "../common/icon";
 import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface CommentFormProps {
-  postId?: number;
-  node?: CommentNodeI; // Can either be the parent, or the editable comment
+  /**
+   * Can either be the parent, or the editable comment. The right side is a postId.
+   */
+  node: Either<CommentNodeI, number>;
   edit?: boolean;
   disabled?: boolean;
   focus?: boolean;
@@ -34,19 +37,19 @@ interface CommentFormProps {
 interface CommentFormState {
   buttonTitle: string;
   finished: boolean;
-  formId: string;
+  formId: Option<string>;
 }
 
 export class CommentForm extends Component<CommentFormProps, CommentFormState> {
   private subscription: Subscription;
   private emptyState: CommentFormState = {
-    buttonTitle: !this.props.node
+    buttonTitle: this.props.node.isRight()
       ? capitalizeFirstLetter(i18n.t("post"))
       : this.props.edit
       ? capitalizeFirstLetter(i18n.t("save"))
       : capitalizeFirstLetter(i18n.t("reply")),
     finished: false,
-    formId: "empty_form",
+    formId: None,
   };
 
   constructor(props: any, context: any) {
@@ -66,26 +69,28 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
   }
 
   render() {
+    let initialContent = this.props.node.match({
+      left: node =>
+        this.props.edit ? Some(node.comment_view.comment.content) : None,
+      right: () => None,
+    });
     return (
       <div class="mb-3">
-        {UserService.Instance.myUserInfo ? (
+        {UserService.Instance.myUserInfo.isSome() ? (
           <MarkdownTextArea
-            initialContent={
-              this.props.edit
-                ? this.props.node.comment_view.comment.content
-                : null
-            }
-            buttonTitle={this.state.buttonTitle}
+            initialContent={initialContent}
+            buttonTitle={Some(this.state.buttonTitle)}
+            maxLength={None}
             finished={this.state.finished}
-            replyType={!!this.props.node}
+            replyType={this.props.node.isLeft()}
             focus={this.props.focus}
             disabled={this.props.disabled}
             onSubmit={this.handleCommentSubmit}
             onReplyCancel={this.handleReplyCancel}
-            placeholder={i18n.t("comment_here")}
+            placeholder={Some(i18n.t("comment_here"))}
           />
         ) : (
-          <div class="alert alert-light" role="alert">
+          <div class="alert alert-warning" role="alert">
             <Icon icon="alert-triangle" classes="icon-inline mr-2" />
             <T i18nKey="must_login" class="d-inline">
               #
@@ -101,28 +106,41 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
 
   handleCommentSubmit(msg: { val: string; formId: string }) {
     let content = msg.val;
-    this.state.formId = msg.formId;
-
-    let node = this.props.node;
-
-    if (this.props.edit) {
-      let form: EditComment = {
-        content,
-        form_id: this.state.formId,
-        comment_id: node.comment_view.comment.id,
-        auth: authField(),
-      };
-      WebSocketService.Instance.send(wsClient.editComment(form));
-    } else {
-      let form: CreateComment = {
-        content,
-        form_id: this.state.formId,
-        post_id: node ? node.comment_view.post.id : this.props.postId,
-        parent_id: node ? node.comment_view.comment.id : null,
-        auth: authField(),
-      };
-      WebSocketService.Instance.send(wsClient.createComment(form));
-    }
+    this.state.formId = Some(msg.formId);
+
+    this.props.node.match({
+      left: node => {
+        if (this.props.edit) {
+          let form = new EditComment({
+            content: Some(content),
+            distinguished: None,
+            form_id: this.state.formId,
+            comment_id: node.comment_view.comment.id,
+            auth: auth().unwrap(),
+          });
+          WebSocketService.Instance.send(wsClient.editComment(form));
+        } else {
+          let form = new CreateComment({
+            content,
+            form_id: this.state.formId,
+            post_id: node.comment_view.post.id,
+            parent_id: Some(node.comment_view.comment.id),
+            auth: auth().unwrap(),
+          });
+          WebSocketService.Instance.send(wsClient.createComment(form));
+        }
+      },
+      right: postId => {
+        let form = new CreateComment({
+          content,
+          form_id: this.state.formId,
+          post_id: postId,
+          parent_id: None,
+          auth: auth().unwrap(),
+        });
+        WebSocketService.Instance.send(wsClient.createComment(form));
+      },
+    });
     this.setState(this.state);
   }
 
@@ -135,15 +153,15 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
     console.log(msg);
 
     // Only do the showing and hiding if logged in
-    if (UserService.Instance.myUserInfo) {
+    if (UserService.Instance.myUserInfo.isSome()) {
       if (
         op == UserOperation.CreateComment ||
         op == UserOperation.EditComment
       ) {
-        let data = wsJsonToRes<CommentResponse>(msg).data;
+        let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
 
         // This only finishes this form, if the randomly generated form_id matches the one received
-        if (this.state.formId == data.form_id) {
+        if (this.state.formId.unwrapOr("") == data.form_id.unwrapOr("")) {
           this.setState({ finished: true });
 
           // Necessary because it broke tribute for some reason
index 1007866708aaedab5299ce6a236421390ef7e886..f654b65a2a35aef80a3f12356caa93a539c9d776 100644 (file)
@@ -1,3 +1,5 @@
+import { Left, None, Option, Some } from "@sniptt/monads";
+import classNames from "classnames";
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
@@ -6,35 +8,49 @@ import {
   BanFromCommunity,
   BanPerson,
   BlockPerson,
+  CommentNode as CommentNodeI,
+  CommentReplyView,
   CommentView,
   CommunityModeratorView,
   CreateCommentLike,
+  CreateCommentReport,
   DeleteComment,
-  MarkCommentAsRead,
+  EditComment,
+  GetComments,
+  ListingType,
+  MarkCommentReplyAsRead,
   MarkPersonMentionAsRead,
   PersonMentionView,
   PersonViewSafe,
+  PurgeComment,
+  PurgePerson,
   RemoveComment,
   SaveComment,
+  toUndefined,
   TransferCommunity,
-  TransferSite,
 } from "lemmy-js-client";
 import moment from "moment";
 import { i18n } from "../../i18next";
-import { BanType, CommentNode as CommentNodeI } from "../../interfaces";
+import { BanType, CommentViewType, PurgeType } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  amCommunityCreator,
+  auth,
+  canAdmin,
   canMod,
   colorList,
-  getUnixTime,
+  commentTreeMaxDepth,
+  futureDaysToUnixTime,
+  isAdmin,
+  isBanned,
   isMod,
   mdToHtml,
+  numToSI,
   setupTippy,
   showScores,
   wsClient,
 } from "../../utils";
-import { Icon, Spinner } from "../common/icon";
+import { Icon, PurgeWarning, Spinner } from "../common/icon";
 import { MomentTime } from "../common/moment-time";
 import { CommunityLink } from "../community/community-link";
 import { PersonListing } from "../person/person-listing";
@@ -45,12 +61,16 @@ interface CommentNodeState {
   showReply: boolean;
   showEdit: boolean;
   showRemoveDialog: boolean;
-  removeReason: string;
+  removeReason: Option<string>;
   showBanDialog: boolean;
   removeData: boolean;
-  banReason: string;
-  banExpires: string;
+  banReason: Option<string>;
+  banExpireDays: Option<number>;
   banType: BanType;
+  showPurgeDialog: boolean;
+  purgeReason: Option<string>;
+  purgeType: PurgeType;
+  purgeLoading: boolean;
   showConfirmTransferSite: boolean;
   showConfirmTransferCommunity: boolean;
   showConfirmAppointAsMod: boolean;
@@ -58,29 +78,29 @@ interface CommentNodeState {
   collapsed: boolean;
   viewSource: boolean;
   showAdvanced: boolean;
-  my_vote: number;
+  showReportDialog: boolean;
+  reportReason: string;
+  my_vote: Option<number>;
   score: number;
   upvotes: number;
   downvotes: number;
-  borderColor: string;
   readLoading: boolean;
   saveLoading: boolean;
 }
 
 interface CommentNodeProps {
   node: CommentNodeI;
+  moderators: Option<CommunityModeratorView[]>;
+  admins: Option<PersonViewSafe[]>;
   noBorder?: boolean;
   noIndent?: boolean;
   viewOnly?: boolean;
   locked?: boolean;
   markable?: boolean;
   showContext?: boolean;
-  moderators: CommunityModeratorView[];
-  admins: PersonViewSafe[];
-  // TODO is this necessary, can't I get it from the node itself?
-  postCreatorId?: number;
   showCommunity?: boolean;
   enableDownvotes: boolean;
+  viewType: CommentViewType;
 }
 
 export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
@@ -88,12 +108,16 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     showReply: false,
     showEdit: false,
     showRemoveDialog: false,
-    removeReason: null,
+    removeReason: None,
     showBanDialog: false,
     removeData: false,
-    banReason: null,
-    banExpires: null,
+    banReason: None,
+    banExpireDays: None,
     banType: BanType.Community,
+    showPurgeDialog: false,
+    purgeLoading: false,
+    purgeReason: None,
+    purgeType: PurgeType.Person,
     collapsed: false,
     viewSource: false,
     showAdvanced: false,
@@ -101,13 +125,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     showConfirmTransferCommunity: false,
     showConfirmAppointAsMod: false,
     showConfirmAppointAsAdmin: false,
+    showReportDialog: false,
+    reportReason: null,
     my_vote: this.props.node.comment_view.my_vote,
     score: this.props.node.comment_view.counts.score,
     upvotes: this.props.node.comment_view.counts.upvotes,
     downvotes: this.props.node.comment_view.counts.downvotes,
-    borderColor: this.props.node.depth
-      ? colorList[this.props.node.depth % colorList.length]
-      : colorList[0],
     readLoading: false,
     saveLoading: false,
   };
@@ -136,37 +159,89 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   render() {
     let node = this.props.node;
     let cv = this.props.node.comment_view;
+
+    let purgeTypeText: string;
+    if (this.state.purgeType == PurgeType.Comment) {
+      purgeTypeText = i18n.t("purge_comment");
+    } else if (this.state.purgeType == PurgeType.Person) {
+      purgeTypeText = `${i18n.t("purge")} ${cv.creator.name}`;
+    }
+
+    let canMod_ = canMod(
+      this.props.moderators,
+      this.props.admins,
+      cv.creator.id
+    );
+    let canModOnSelf = canMod(
+      this.props.moderators,
+      this.props.admins,
+      cv.creator.id,
+      UserService.Instance.myUserInfo,
+      true
+    );
+    let canAdmin_ = canAdmin(this.props.admins, cv.creator.id);
+    let canAdminOnSelf = canAdmin(
+      this.props.admins,
+      cv.creator.id,
+      UserService.Instance.myUserInfo,
+      true
+    );
+    let isMod_ = isMod(this.props.moderators, cv.creator.id);
+    let isAdmin_ = isAdmin(this.props.admins, cv.creator.id);
+    let amCommunityCreator_ = amCommunityCreator(
+      this.props.moderators,
+      cv.creator.id
+    );
+
+    let borderColor = this.props.node.depth
+      ? colorList[(this.props.node.depth - 1) % colorList.length]
+      : colorList[0];
+    let moreRepliesBorderColor = this.props.node.depth
+      ? colorList[this.props.node.depth % colorList.length]
+      : colorList[0];
+
+    let showMoreChildren =
+      this.props.viewType == CommentViewType.Tree &&
+      !this.state.collapsed &&
+      node.children.length == 0 &&
+      node.comment_view.counts.child_count > 0;
+
     return (
       <div
         className={`comment ${
-          cv.comment.parent_id && !this.props.noIndent ? "ml-1" : ""
+          this.props.node.depth && !this.props.noIndent ? "ml-1" : ""
         }`}
       >
         <div
           id={`comment-${cv.comment.id}`}
-          className={`details comment-node py-2 ${
-            !this.props.noBorder ? "border-top border-light" : ""
-          } ${this.isCommentNew ? "mark" : ""}`}
+          className={classNames(`details comment-node py-2`, {
+            "border-top border-light": !this.props.noBorder,
+            mark:
+              this.isCommentNew ||
+              this.props.node.comment_view.comment.distinguished,
+          })}
           style={
             !this.props.noIndent &&
-            cv.comment.parent_id &&
-            `border-left: 2px ${this.state.borderColor} solid !important`
+            this.props.node.depth &&
+            `border-left: 2px ${borderColor} solid !important`
           }
         >
           <div
-            class={`${!this.props.noIndent && cv.comment.parent_id && "ml-2"}`}
+            class={`${!this.props.noIndent && this.props.node.depth && "ml-2"}`}
           >
             <div class="d-flex flex-wrap align-items-center text-muted small">
               <span class="mr-2">
                 <PersonListing person={cv.creator} />
               </span>
-
-              {this.isMod && (
+              {cv.comment.distinguished && (
+                <Icon icon="shield" inline classes={`text-danger mr-2`} />
+              )}
+              {isMod_ && (
                 <div className="badge badge-light d-none d-sm-inline mr-2">
                   {i18n.t("mod")}
                 </div>
               )}
-              {this.isAdmin && (
+              {isAdmin_ && (
                 <div className="badge badge-light d-none d-sm-inline mr-2">
                   {i18n.t("admin")}
                 </div>
@@ -176,7 +251,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                   {i18n.t("creator")}
                 </div>
               )}
-              {(cv.creator_banned_from_community || cv.creator.banned) && (
+              {cv.creator.bot_account && (
+                <div className="badge badge-light d-none d-sm-inline mr-2">
+                  {i18n.t("bot_account").toLowerCase()}
+                </div>
+              )}
+              {(cv.creator_banned_from_community || isBanned(cv.creator)) && (
                 <div className="badge badge-danger mr-2">
                   {i18n.t("banned")}
                 </div>
@@ -210,29 +290,33 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                 <>
                   <a
                     className={`unselectable pointer ${this.scoreColor}`}
-                    onClick={linkEvent(node, this.handleCommentUpvote)}
+                    onClick={this.handleCommentUpvote}
                     data-tippy-content={this.pointsTippy}
                   >
                     <span
                       class="mr-1 font-weight-bold"
                       aria-label={i18n.t("number_of_points", {
                         count: this.state.score,
+                        formattedCount: this.state.score,
                       })}
                     >
-                      {this.state.score}
+                      {numToSI(this.state.score)}
                     </span>
                   </a>
                   <span className="mr-1">•</span>
                 </>
               )}
               <span>
-                <MomentTime data={cv.comment} />
+                <MomentTime
+                  published={cv.comment.published}
+                  updated={cv.comment.updated}
+                />
               </span>
             </div>
             {/* end of user row */}
             {this.state.showEdit && (
               <CommentForm
-                node={node}
+                node={Left(node)}
                 edit
                 onReplyCancel={this.handleReplyCancel}
                 disabled={this.props.locked}
@@ -258,12 +342,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                       class="btn btn-link btn-animate text-muted"
                       onClick={linkEvent(this, this.handleMarkRead)}
                       data-tippy-content={
-                        this.commentOrMentionRead
+                        this.commentReplyOrMentionRead
                           ? i18n.t("mark_as_unread")
                           : i18n.t("mark_as_read")
                       }
                       aria-label={
-                        this.commentOrMentionRead
+                        this.commentReplyOrMentionRead
                           ? i18n.t("mark_as_unread")
                           : i18n.t("mark_as_read")
                       }
@@ -274,443 +358,492 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                         <Icon
                           icon="check"
                           classes={`icon-inline ${
-                            this.commentOrMentionRead && "text-success"
+                            this.commentReplyOrMentionRead && "text-success"
                           }`}
                         />
                       )}
                     </button>
                   )}
-                  {UserService.Instance.myUserInfo && !this.props.viewOnly && (
-                    <>
-                      <button
-                        className={`btn btn-link btn-animate ${
-                          this.state.my_vote == 1 ? "text-info" : "text-muted"
-                        }`}
-                        onClick={linkEvent(node, this.handleCommentUpvote)}
-                        data-tippy-content={i18n.t("upvote")}
-                        aria-label={i18n.t("upvote")}
-                      >
-                        <Icon icon="arrow-up1" classes="icon-inline" />
-                        {showScores() &&
-                          this.state.upvotes !== this.state.score && (
-                            <span class="ml-1">{this.state.upvotes}</span>
-                          )}
-                      </button>
-                      {this.props.enableDownvotes && (
+                  {UserService.Instance.myUserInfo.isSome() &&
+                    !this.props.viewOnly && (
+                      <>
                         <button
                           className={`btn btn-link btn-animate ${
-                            this.state.my_vote == -1
-                              ? "text-danger"
+                            this.state.my_vote.unwrapOr(0) == 1
+                              ? "text-info"
                               : "text-muted"
                           }`}
-                          onClick={linkEvent(node, this.handleCommentDownvote)}
-                          data-tippy-content={i18n.t("downvote")}
-                          aria-label={i18n.t("downvote")}
+                          onClick={this.handleCommentUpvote}
+                          data-tippy-content={i18n.t("upvote")}
+                          aria-label={i18n.t("upvote")}
                         >
-                          <Icon icon="arrow-down1" classes="icon-inline" />
+                          <Icon icon="arrow-up1" classes="icon-inline" />
                           {showScores() &&
                             this.state.upvotes !== this.state.score && (
-                              <span class="ml-1">{this.state.downvotes}</span>
+                              <span class="ml-1">
+                                {numToSI(this.state.upvotes)}
+                              </span>
                             )}
                         </button>
-                      )}
-                      <button
-                        class="btn btn-link btn-animate text-muted"
-                        onClick={linkEvent(this, this.handleReplyClick)}
-                        data-tippy-content={i18n.t("reply")}
-                        aria-label={i18n.t("reply")}
-                      >
-                        <Icon icon="reply1" classes="icon-inline" />
-                      </button>
-                      {!this.state.showAdvanced ? (
-                        <button
-                          className="btn btn-link btn-animate text-muted"
-                          onClick={linkEvent(this, this.handleShowAdvanced)}
-                          data-tippy-content={i18n.t("more")}
-                          aria-label={i18n.t("more")}
-                        >
-                          <Icon icon="more-vertical" classes="icon-inline" />
-                        </button>
-                      ) : (
-                        <>
-                          {!this.myComment && (
-                            <>
-                              <button class="btn btn-link btn-animate">
-                                <Link
-                                  className="text-muted"
-                                  to={`/create_private_message/recipient/${cv.creator.id}`}
-                                  title={i18n.t("message").toLowerCase()}
-                                >
-                                  <Icon icon="mail" />
-                                </Link>
-                              </button>
-                              <button
-                                class="btn btn-link btn-animate text-muted"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleBlockUserClick
-                                )}
-                                data-tippy-content={i18n.t("block_user")}
-                                aria-label={i18n.t("block_user")}
-                              >
-                                <Icon icon="slash" />
-                              </button>
-                            </>
-                          )}
+                        {this.props.enableDownvotes && (
                           <button
-                            class="btn btn-link btn-animate text-muted"
-                            onClick={linkEvent(
-                              this,
-                              this.handleSaveCommentClick
-                            )}
-                            data-tippy-content={
-                              cv.saved ? i18n.t("unsave") : i18n.t("save")
-                            }
-                            aria-label={
-                              cv.saved ? i18n.t("unsave") : i18n.t("save")
-                            }
+                            className={`btn btn-link btn-animate ${
+                              this.state.my_vote.unwrapOr(0) == -1
+                                ? "text-danger"
+                                : "text-muted"
+                            }`}
+                            onClick={this.handleCommentDownvote}
+                            data-tippy-content={i18n.t("downvote")}
+                            aria-label={i18n.t("downvote")}
                           >
-                            {this.state.saveLoading ? (
-                              this.loadingIcon
-                            ) : (
-                              <Icon
-                                icon="star"
-                                classes={`icon-inline ${
-                                  cv.saved && "text-warning"
-                                }`}
-                              />
-                            )}
+                            <Icon icon="arrow-down1" classes="icon-inline" />
+                            {showScores() &&
+                              this.state.upvotes !== this.state.score && (
+                                <span class="ml-1">
+                                  {numToSI(this.state.downvotes)}
+                                </span>
+                              )}
                           </button>
+                        )}
+                        <button
+                          class="btn btn-link btn-animate text-muted"
+                          onClick={linkEvent(this, this.handleReplyClick)}
+                          data-tippy-content={i18n.t("reply")}
+                          aria-label={i18n.t("reply")}
+                        >
+                          <Icon icon="reply1" classes="icon-inline" />
+                        </button>
+                        {!this.state.showAdvanced ? (
                           <button
                             className="btn btn-link btn-animate text-muted"
-                            onClick={linkEvent(this, this.handleViewSource)}
-                            data-tippy-content={i18n.t("view_source")}
-                            aria-label={i18n.t("view_source")}
+                            onClick={linkEvent(this, this.handleShowAdvanced)}
+                            data-tippy-content={i18n.t("more")}
+                            aria-label={i18n.t("more")}
                           >
-                            <Icon
-                              icon="file-text"
-                              classes={`icon-inline ${
-                                this.state.viewSource && "text-success"
-                              }`}
-                            />
+                            <Icon icon="more-vertical" classes="icon-inline" />
                           </button>
-                          {this.myComment && (
-                            <>
-                              <button
-                                class="btn btn-link btn-animate text-muted"
-                                onClick={linkEvent(this, this.handleEditClick)}
-                                data-tippy-content={i18n.t("edit")}
-                                aria-label={i18n.t("edit")}
-                              >
-                                <Icon icon="edit" classes="icon-inline" />
-                              </button>
-                              <button
-                                class="btn btn-link btn-animate text-muted"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleDeleteClick
-                                )}
-                                data-tippy-content={
-                                  !cv.comment.deleted
-                                    ? i18n.t("delete")
-                                    : i18n.t("restore")
-                                }
-                                aria-label={
-                                  !cv.comment.deleted
-                                    ? i18n.t("delete")
-                                    : i18n.t("restore")
-                                }
-                              >
+                        ) : (
+                          <>
+                            {!this.myComment && (
+                              <>
+                                <button class="btn btn-link btn-animate">
+                                  <Link
+                                    className="text-muted"
+                                    to={`/create_private_message/recipient/${cv.creator.id}`}
+                                    title={i18n.t("message").toLowerCase()}
+                                  >
+                                    <Icon icon="mail" />
+                                  </Link>
+                                </button>
+                                <button
+                                  class="btn btn-link btn-animate text-muted"
+                                  onClick={linkEvent(
+                                    this,
+                                    this.handleShowReportDialog
+                                  )}
+                                  data-tippy-content={i18n.t(
+                                    "show_report_dialog"
+                                  )}
+                                  aria-label={i18n.t("show_report_dialog")}
+                                >
+                                  <Icon icon="flag" />
+                                </button>
+                                <button
+                                  class="btn btn-link btn-animate text-muted"
+                                  onClick={linkEvent(
+                                    this,
+                                    this.handleBlockUserClick
+                                  )}
+                                  data-tippy-content={i18n.t("block_user")}
+                                  aria-label={i18n.t("block_user")}
+                                >
+                                  <Icon icon="slash" />
+                                </button>
+                              </>
+                            )}
+                            <button
+                              class="btn btn-link btn-animate text-muted"
+                              onClick={linkEvent(
+                                this,
+                                this.handleSaveCommentClick
+                              )}
+                              data-tippy-content={
+                                cv.saved ? i18n.t("unsave") : i18n.t("save")
+                              }
+                              aria-label={
+                                cv.saved ? i18n.t("unsave") : i18n.t("save")
+                              }
+                            >
+                              {this.state.saveLoading ? (
+                                this.loadingIcon
+                              ) : (
                                 <Icon
-                                  icon="trash"
+                                  icon="star"
                                   classes={`icon-inline ${
-                                    cv.comment.deleted && "text-danger"
+                                    cv.saved && "text-warning"
                                   }`}
                                 />
-                              </button>
-                            </>
-                          )}
-                          {/* Admins and mods can remove comments */}
-                          {(this.canMod || this.canAdmin) && (
-                            <>
-                              {!cv.comment.removed ? (
+                              )}
+                            </button>
+                            <button
+                              className="btn btn-link btn-animate text-muted"
+                              onClick={linkEvent(this, this.handleViewSource)}
+                              data-tippy-content={i18n.t("view_source")}
+                              aria-label={i18n.t("view_source")}
+                            >
+                              <Icon
+                                icon="file-text"
+                                classes={`icon-inline ${
+                                  this.state.viewSource && "text-success"
+                                }`}
+                              />
+                            </button>
+                            {this.myComment && (
+                              <>
                                 <button
                                   class="btn btn-link btn-animate text-muted"
                                   onClick={linkEvent(
                                     this,
-                                    this.handleModRemoveShow
+                                    this.handleEditClick
                                   )}
-                                  aria-label={i18n.t("remove")}
+                                  data-tippy-content={i18n.t("edit")}
+                                  aria-label={i18n.t("edit")}
                                 >
-                                  {i18n.t("remove")}
+                                  <Icon icon="edit" classes="icon-inline" />
                                 </button>
-                              ) : (
                                 <button
                                   class="btn btn-link btn-animate text-muted"
                                   onClick={linkEvent(
                                     this,
-                                    this.handleModRemoveSubmit
+                                    this.handleDeleteClick
                                   )}
-                                  aria-label={i18n.t("restore")}
+                                  data-tippy-content={
+                                    !cv.comment.deleted
+                                      ? i18n.t("delete")
+                                      : i18n.t("restore")
+                                  }
+                                  aria-label={
+                                    !cv.comment.deleted
+                                      ? i18n.t("delete")
+                                      : i18n.t("restore")
+                                  }
                                 >
-                                  {i18n.t("restore")}
+                                  <Icon
+                                    icon="trash"
+                                    classes={`icon-inline ${
+                                      cv.comment.deleted && "text-danger"
+                                    }`}
+                                  />
                                 </button>
-                              )}
-                            </>
-                          )}
-                          {/* Mods can ban from community, and appoint as mods to community */}
-                          {this.canMod && (
-                            <>
-                              {!this.isMod &&
-                                (!cv.creator_banned_from_community ? (
+
+                                {(canModOnSelf || canAdminOnSelf) && (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
                                     onClick={linkEvent(
                                       this,
-                                      this.handleModBanFromCommunityShow
+                                      this.handleDistinguishClick
                                     )}
-                                    aria-label={i18n.t("ban")}
+                                    data-tippy-content={
+                                      !cv.comment.distinguished
+                                        ? i18n.t("distinguish")
+                                        : i18n.t("undistinguish")
+                                    }
+                                    aria-label={
+                                      !cv.comment.distinguished
+                                        ? i18n.t("distinguish")
+                                        : i18n.t("undistinguish")
+                                    }
                                   >
-                                    {i18n.t("ban")}
+                                    <Icon
+                                      icon="shield"
+                                      classes={`icon-inline ${
+                                        cv.comment.distinguished &&
+                                        "text-danger"
+                                      }`}
+                                    />
                                   </button>
-                                ) : (
+                                )}
+                              </>
+                            )}
+                            {/* Admins and mods can remove comments */}
+                            {(canMod_ || canAdmin_) && (
+                              <>
+                                {!cv.comment.removed ? (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
                                     onClick={linkEvent(
                                       this,
-                                      this.handleModBanFromCommunitySubmit
+                                      this.handleModRemoveShow
                                     )}
-                                    aria-label={i18n.t("unban")}
+                                    aria-label={i18n.t("remove")}
                                   >
-                                    {i18n.t("unban")}
+                                    {i18n.t("remove")}
                                   </button>
-                                ))}
-                              {!cv.creator_banned_from_community &&
-                                (!this.state.showConfirmAppointAsMod ? (
+                                ) : (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
                                     onClick={linkEvent(
                                       this,
-                                      this.handleShowConfirmAppointAsMod
+                                      this.handleModRemoveSubmit
                                     )}
-                                    aria-label={
-                                      this.isMod
-                                        ? i18n.t("remove_as_mod")
-                                        : i18n.t("appoint_as_mod")
-                                    }
+                                    aria-label={i18n.t("restore")}
                                   >
-                                    {this.isMod
-                                      ? i18n.t("remove_as_mod")
-                                      : i18n.t("appoint_as_mod")}
+                                    {i18n.t("restore")}
                                   </button>
-                                ) : (
-                                  <>
+                                )}
+                              </>
+                            )}
+                            {/* Mods can ban from community, and appoint as mods to community */}
+                            {canMod_ && (
+                              <>
+                                {!isMod_ &&
+                                  (!cv.creator_banned_from_community ? (
                                     <button
                                       class="btn btn-link btn-animate text-muted"
-                                      aria-label={i18n.t("are_you_sure")}
+                                      onClick={linkEvent(
+                                        this,
+                                        this.handleModBanFromCommunityShow
+                                      )}
+                                      aria-label={i18n.t("ban")}
                                     >
-                                      {i18n.t("are_you_sure")}
+                                      {i18n.t("ban")}
                                     </button>
+                                  ) : (
                                     <button
                                       class="btn btn-link btn-animate text-muted"
                                       onClick={linkEvent(
                                         this,
-                                        this.handleAddModToCommunity
+                                        this.handleModBanFromCommunitySubmit
                                       )}
-                                      aria-label={i18n.t("yes")}
+                                      aria-label={i18n.t("unban")}
                                     >
-                                      {i18n.t("yes")}
+                                      {i18n.t("unban")}
                                     </button>
+                                  ))}
+                                {!cv.creator_banned_from_community &&
+                                  (!this.state.showConfirmAppointAsMod ? (
                                     <button
                                       class="btn btn-link btn-animate text-muted"
                                       onClick={linkEvent(
                                         this,
-                                        this.handleCancelConfirmAppointAsMod
+                                        this.handleShowConfirmAppointAsMod
                                       )}
-                                      aria-label={i18n.t("no")}
+                                      aria-label={
+                                        isMod_
+                                          ? i18n.t("remove_as_mod")
+                                          : i18n.t("appoint_as_mod")
+                                      }
                                     >
-                                      {i18n.t("no")}
+                                      {isMod_
+                                        ? i18n.t("remove_as_mod")
+                                        : i18n.t("appoint_as_mod")}
                                     </button>
-                                  </>
-                                ))}
-                            </>
-                          )}
-                          {/* Community creators and admins can transfer community to another mod */}
-                          {(this.amCommunityCreator || this.canAdmin) &&
-                            this.isMod &&
-                            cv.creator.local &&
-                            (!this.state.showConfirmTransferCommunity ? (
-                              <button
-                                class="btn btn-link btn-animate text-muted"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleShowConfirmTransferCommunity
-                                )}
-                                aria-label={i18n.t("transfer_community")}
-                              >
-                                {i18n.t("transfer_community")}
-                              </button>
-                            ) : (
-                              <>
-                                <button
-                                  class="btn btn-link btn-animate text-muted"
-                                  aria-label={i18n.t("are_you_sure")}
-                                >
-                                  {i18n.t("are_you_sure")}
-                                </button>
-                                <button
-                                  class="btn btn-link btn-animate text-muted"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleTransferCommunity
-                                  )}
-                                  aria-label={i18n.t("yes")}
-                                >
-                                  {i18n.t("yes")}
-                                </button>
+                                  ) : (
+                                    <>
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        aria-label={i18n.t("are_you_sure")}
+                                      >
+                                        {i18n.t("are_you_sure")}
+                                      </button>
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        onClick={linkEvent(
+                                          this,
+                                          this.handleAddModToCommunity
+                                        )}
+                                        aria-label={i18n.t("yes")}
+                                      >
+                                        {i18n.t("yes")}
+                                      </button>
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        onClick={linkEvent(
+                                          this,
+                                          this.handleCancelConfirmAppointAsMod
+                                        )}
+                                        aria-label={i18n.t("no")}
+                                      >
+                                        {i18n.t("no")}
+                                      </button>
+                                    </>
+                                  ))}
+                              </>
+                            )}
+                            {/* Community creators and admins can transfer community to another mod */}
+                            {(amCommunityCreator_ || canAdmin_) &&
+                              isMod_ &&
+                              cv.creator.local &&
+                              (!this.state.showConfirmTransferCommunity ? (
                                 <button
                                   class="btn btn-link btn-animate text-muted"
                                   onClick={linkEvent(
                                     this,
-                                    this
-                                      .handleCancelShowConfirmTransferCommunity
+                                    this.handleShowConfirmTransferCommunity
                                   )}
-                                  aria-label={i18n.t("no")}
+                                  aria-label={i18n.t("transfer_community")}
                                 >
-                                  {i18n.t("no")}
+                                  {i18n.t("transfer_community")}
                                 </button>
-                              </>
-                            ))}
-                          {/* Admins can ban from all, and appoint other admins */}
-                          {this.canAdmin && (
-                            <>
-                              {!this.isAdmin &&
-                                (!cv.creator.banned ? (
+                              ) : (
+                                <>
                                   <button
                                     class="btn btn-link btn-animate text-muted"
-                                    onClick={linkEvent(
-                                      this,
-                                      this.handleModBanShow
-                                    )}
-                                    aria-label={i18n.t("ban_from_site")}
+                                    aria-label={i18n.t("are_you_sure")}
                                   >
-                                    {i18n.t("ban_from_site")}
+                                    {i18n.t("are_you_sure")}
                                   </button>
-                                ) : (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
                                     onClick={linkEvent(
                                       this,
-                                      this.handleModBanSubmit
+                                      this.handleTransferCommunity
                                     )}
-                                    aria-label={i18n.t("unban_from_site")}
+                                    aria-label={i18n.t("yes")}
                                   >
-                                    {i18n.t("unban_from_site")}
+                                    {i18n.t("yes")}
                                   </button>
-                                ))}
-                              {!cv.creator.banned &&
-                                cv.creator.local &&
-                                (!this.state.showConfirmAppointAsAdmin ? (
                                   <button
                                     class="btn btn-link btn-animate text-muted"
                                     onClick={linkEvent(
                                       this,
-                                      this.handleShowConfirmAppointAsAdmin
+                                      this
+                                        .handleCancelShowConfirmTransferCommunity
                                     )}
-                                    aria-label={
-                                      this.isAdmin
-                                        ? i18n.t("remove_as_admin")
-                                        : i18n.t("appoint_as_admin")
-                                    }
+                                    aria-label={i18n.t("no")}
                                   >
-                                    {this.isAdmin
-                                      ? i18n.t("remove_as_admin")
-                                      : i18n.t("appoint_as_admin")}
+                                    {i18n.t("no")}
                                   </button>
-                                ) : (
+                                </>
+                              ))}
+                            {/* Admins can ban from all, and appoint other admins */}
+                            {canAdmin_ && (
+                              <>
+                                {!isAdmin_ && (
                                   <>
-                                    <button class="btn btn-link btn-animate text-muted">
-                                      {i18n.t("are_you_sure")}
-                                    </button>
                                     <button
                                       class="btn btn-link btn-animate text-muted"
                                       onClick={linkEvent(
                                         this,
-                                        this.handleAddAdmin
+                                        this.handlePurgePersonShow
                                       )}
-                                      aria-label={i18n.t("yes")}
+                                      aria-label={i18n.t("purge_user")}
                                     >
-                                      {i18n.t("yes")}
+                                      {i18n.t("purge_user")}
                                     </button>
                                     <button
                                       class="btn btn-link btn-animate text-muted"
                                       onClick={linkEvent(
                                         this,
-                                        this.handleCancelConfirmAppointAsAdmin
+                                        this.handlePurgeCommentShow
                                       )}
-                                      aria-label={i18n.t("no")}
+                                      aria-label={i18n.t("purge_comment")}
                                     >
-                                      {i18n.t("no")}
+                                      {i18n.t("purge_comment")}
                                     </button>
+
+                                    {!isBanned(cv.creator) ? (
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        onClick={linkEvent(
+                                          this,
+                                          this.handleModBanShow
+                                        )}
+                                        aria-label={i18n.t("ban_from_site")}
+                                      >
+                                        {i18n.t("ban_from_site")}
+                                      </button>
+                                    ) : (
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        onClick={linkEvent(
+                                          this,
+                                          this.handleModBanSubmit
+                                        )}
+                                        aria-label={i18n.t("unban_from_site")}
+                                      >
+                                        {i18n.t("unban_from_site")}
+                                      </button>
+                                    )}
                                   </>
-                                ))}
-                            </>
-                          )}
-                          {/* Site Creator can transfer to another admin */}
-                          {this.amSiteCreator &&
-                            this.isAdmin &&
-                            cv.creator.local &&
-                            (!this.state.showConfirmTransferSite ? (
-                              <button
-                                class="btn btn-link btn-animate text-muted"
-                                onClick={linkEvent(
-                                  this,
-                                  this.handleShowConfirmTransferSite
                                 )}
-                                aria-label={i18n.t("transfer_site")}
-                              >
-                                {i18n.t("transfer_site")}
-                              </button>
-                            ) : (
-                              <>
-                                <button
-                                  class="btn btn-link btn-animate text-muted"
-                                  aria-label={i18n.t("are_you_sure")}
-                                >
-                                  {i18n.t("are_you_sure")}
-                                </button>
-                                <button
-                                  class="btn btn-link btn-animate text-muted"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleTransferSite
-                                  )}
-                                  aria-label={i18n.t("yes")}
-                                >
-                                  {i18n.t("yes")}
-                                </button>
-                                <button
-                                  class="btn btn-link btn-animate text-muted"
-                                  onClick={linkEvent(
-                                    this,
-                                    this.handleCancelShowConfirmTransferSite
-                                  )}
-                                  aria-label={i18n.t("no")}
-                                >
-                                  {i18n.t("no")}
-                                </button>
+                                {!isBanned(cv.creator) &&
+                                  cv.creator.local &&
+                                  (!this.state.showConfirmAppointAsAdmin ? (
+                                    <button
+                                      class="btn btn-link btn-animate text-muted"
+                                      onClick={linkEvent(
+                                        this,
+                                        this.handleShowConfirmAppointAsAdmin
+                                      )}
+                                      aria-label={
+                                        isAdmin_
+                                          ? i18n.t("remove_as_admin")
+                                          : i18n.t("appoint_as_admin")
+                                      }
+                                    >
+                                      {isAdmin_
+                                        ? i18n.t("remove_as_admin")
+                                        : i18n.t("appoint_as_admin")}
+                                    </button>
+                                  ) : (
+                                    <>
+                                      <button class="btn btn-link btn-animate text-muted">
+                                        {i18n.t("are_you_sure")}
+                                      </button>
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        onClick={linkEvent(
+                                          this,
+                                          this.handleAddAdmin
+                                        )}
+                                        aria-label={i18n.t("yes")}
+                                      >
+                                        {i18n.t("yes")}
+                                      </button>
+                                      <button
+                                        class="btn btn-link btn-animate text-muted"
+                                        onClick={linkEvent(
+                                          this,
+                                          this.handleCancelConfirmAppointAsAdmin
+                                        )}
+                                        aria-label={i18n.t("no")}
+                                      >
+                                        {i18n.t("no")}
+                                      </button>
+                                    </>
+                                  ))}
                               </>
-                            ))}
-                        </>
-                      )}
-                    </>
-                  )}
+                            )}
+                          </>
+                        )}
+                      </>
+                    )}
                 </div>
                 {/* end of button group */}
               </div>
             )}
           </div>
         </div>
+        {showMoreChildren && (
+          <div
+            className={`details ml-1 comment-node py-2 ${
+              !this.props.noBorder ? "border-top border-light" : ""
+            }`}
+            style={`border-left: 2px ${moreRepliesBorderColor} solid !important`}
+          >
+            <button
+              class="btn btn-link text-muted"
+              onClick={linkEvent(this, this.handleFetchChildren)}
+            >
+              {i18n.t("x_more_replies", {
+                count: node.comment_view.counts.child_count,
+                formattedCount: numToSI(node.comment_view.counts.child_count),
+              })}{" "}
+              ➔
+            </button>
+          </div>
+        )}
         {/* end of details */}
         {this.state.showRemoveDialog && (
           <form
@@ -728,7 +861,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
               id={`mod-remove-reason-${cv.comment.id}`}
               class="form-control mr-2"
               placeholder={i18n.t("reason")}
-              value={this.state.removeReason}
+              value={toUndefined(this.state.removeReason)}
               onInput={linkEvent(this, this.handleModRemoveReasonChange)}
             />
             <button
@@ -740,9 +873,35 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
             </button>
           </form>
         )}
+        {this.state.showReportDialog && (
+          <form
+            class="form-inline"
+            onSubmit={linkEvent(this, this.handleReportSubmit)}
+          >
+            <label class="sr-only" htmlFor={`report-reason-${cv.comment.id}`}>
+              {i18n.t("reason")}
+            </label>
+            <input
+              type="text"
+              required
+              id={`report-reason-${cv.comment.id}`}
+              class="form-control mr-2"
+              placeholder={i18n.t("reason")}
+              value={this.state.reportReason}
+              onInput={linkEvent(this, this.handleReportReasonChange)}
+            />
+            <button
+              type="submit"
+              class="btn btn-secondary"
+              aria-label={i18n.t("create_report")}
+            >
+              {i18n.t("create_report")}
+            </button>
+          </form>
+        )}
         {this.state.showBanDialog && (
           <form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
-            <div class="form-group row">
+            <div class="form-group row col-12">
               <label
                 class="col-form-label"
                 htmlFor={`mod-ban-reason-${cv.comment.id}`}
@@ -754,9 +913,23 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
                 id={`mod-ban-reason-${cv.comment.id}`}
                 class="form-control mr-2"
                 placeholder={i18n.t("reason")}
-                value={this.state.banReason}
+                value={toUndefined(this.state.banReason)}
                 onInput={linkEvent(this, this.handleModBanReasonChange)}
               />
+              <label
+                class="col-form-label"
+                htmlFor={`mod-ban-expires-${cv.comment.id}`}
+              >
+                {i18n.t("expires")}
+              </label>
+              <input
+                type="number"
+                id={`mod-ban-expires-${cv.comment.id}`}
+                class="form-control mr-2"
+                placeholder={i18n.t("number_of_days")}
+                value={toUndefined(this.state.banExpireDays)}
+                onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
+              />
               <div class="form-group">
                 <div class="form-check">
                   <input
@@ -792,22 +965,53 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
             </div>
           </form>
         )}
+
+        {this.state.showPurgeDialog && (
+          <form onSubmit={linkEvent(this, this.handlePurgeSubmit)}>
+            <PurgeWarning />
+            <label class="sr-only" htmlFor="purge-reason">
+              {i18n.t("reason")}
+            </label>
+            <input
+              type="text"
+              id="purge-reason"
+              class="form-control my-3"
+              placeholder={i18n.t("reason")}
+              value={toUndefined(this.state.purgeReason)}
+              onInput={linkEvent(this, this.handlePurgeReasonChange)}
+            />
+            <div class="form-group row col-12">
+              {this.state.purgeLoading ? (
+                <Spinner />
+              ) : (
+                <button
+                  type="submit"
+                  class="btn btn-secondary"
+                  aria-label={purgeTypeText}
+                >
+                  {purgeTypeText}
+                </button>
+              )}
+            </div>
+          </form>
+        )}
         {this.state.showReply && (
           <CommentForm
-            node={node}
+            node={Left(node)}
             onReplyCancel={this.handleReplyCancel}
             disabled={this.props.locked}
             focus
           />
         )}
-        {node.children && !this.state.collapsed && (
+        {!this.state.collapsed && node.children.length > 0 && (
           <CommentNodes
             nodes={node.children}
             locked={this.props.locked}
             moderators={this.props.moderators}
             admins={this.props.admins}
-            postCreatorId={this.props.postCreatorId}
+            maxCommentsShown={None}
             enableDownvotes={this.props.enableDownvotes}
+            viewType={this.props.viewType}
           />
         )}
         {/* A collapsed clearfix */}
@@ -816,23 +1020,43 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     );
   }
 
-  get commentOrMentionRead() {
+  get commentReplyOrMentionRead(): boolean {
     let cv = this.props.node.comment_view;
-    return this.isPersonMentionType(cv)
-      ? cv.person_mention.read
-      : cv.comment.read;
+
+    if (this.isPersonMentionType(cv)) {
+      return cv.person_mention.read;
+    } else if (this.isCommentReplyType(cv)) {
+      return cv.comment_reply.read;
+    } else {
+      return false;
+    }
   }
 
   linkBtn(small = false) {
     let cv = this.props.node.comment_view;
+    let classnames = classNames("btn btn-link btn-animate text-muted", {
+      "btn-sm": small,
+    });
+
+    let title = this.props.showContext
+      ? i18n.t("show_context")
+      : i18n.t("link");
+
     return (
-      <Link
-        className={`btn ${small && "btn-sm"} btn-link btn-animate text-muted`}
-        to={`/post/${cv.post.id}/comment/${cv.comment.id}`}
-        title={this.props.showContext ? i18n.t("show_context") : i18n.t("link")}
-      >
-        <Icon icon="link" classes="icon-inline" />
-      </Link>
+      <>
+        <Link
+          className={classnames}
+          to={`/comment/${cv.comment.id}`}
+          title={title}
+        >
+          <Icon icon="link" classes="icon-inline" />
+        </Link>
+        {
+          <a className={classnames} title={title} href={cv.comment.ap_id}>
+            <Icon icon="fedilink" classes="icon-inline" />
+          </a>
+        }
+      </>
     );
   }
 
@@ -841,82 +1065,18 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   }
 
   get myComment(): boolean {
-    return (
-      this.props.node.comment_view.creator.id ==
-      UserService.Instance.myUserInfo?.local_user_view.person.id
-    );
-  }
-
-  get isMod(): boolean {
-    return (
-      this.props.moderators &&
-      isMod(
-        this.props.moderators.map(m => m.moderator.id),
-        this.props.node.comment_view.creator.id
+    return UserService.Instance.myUserInfo
+      .map(
+        m =>
+          m.local_user_view.person.id == this.props.node.comment_view.creator.id
       )
-    );
-  }
-
-  get isAdmin(): boolean {
-    return (
-      this.props.admins &&
-      isMod(
-        this.props.admins.map(a => a.person.id),
-        this.props.node.comment_view.creator.id
-      )
-    );
+      .unwrapOr(false);
   }
 
   get isPostCreator(): boolean {
-    return this.props.node.comment_view.creator.id == this.props.postCreatorId;
-  }
-
-  get canMod(): boolean {
-    if (this.props.admins && this.props.moderators) {
-      let adminsThenMods = this.props.admins
-        .map(a => a.person.id)
-        .concat(this.props.moderators.map(m => m.moderator.id));
-
-      return canMod(
-        UserService.Instance.myUserInfo,
-        adminsThenMods,
-        this.props.node.comment_view.creator.id
-      );
-    } else {
-      return false;
-    }
-  }
-
-  get canAdmin(): boolean {
     return (
-      this.props.admins &&
-      canMod(
-        UserService.Instance.myUserInfo,
-        this.props.admins.map(a => a.person.id),
-        this.props.node.comment_view.creator.id
-      )
-    );
-  }
-
-  get amCommunityCreator(): boolean {
-    return (
-      this.props.moderators &&
-      UserService.Instance.myUserInfo &&
-      this.props.node.comment_view.creator.id !=
-        UserService.Instance.myUserInfo.local_user_view.person.id &&
-      UserService.Instance.myUserInfo.local_user_view.person.id ==
-        this.props.moderators[0].moderator.id
-    );
-  }
-
-  get amSiteCreator(): boolean {
-    return (
-      this.props.admins &&
-      UserService.Instance.myUserInfo &&
-      this.props.node.comment_view.creator.id !=
-        UserService.Instance.myUserInfo.local_user_view.person.id &&
-      UserService.Instance.myUserInfo.local_user_view.person.id ==
-        this.props.admins[0].person.id
+      this.props.node.comment_view.creator.id ==
+      this.props.node.comment_view.post.creator_id
     );
   }
 
@@ -940,32 +1100,32 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   }
 
   handleBlockUserClick(i: CommentNode) {
-    let blockUserForm: BlockPerson = {
+    let blockUserForm = new BlockPerson({
       person_id: i.props.node.comment_view.creator.id,
       block: true,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
   }
 
   handleDeleteClick(i: CommentNode) {
     let comment = i.props.node.comment_view.comment;
-    let deleteForm: DeleteComment = {
+    let deleteForm = new DeleteComment({
       comment_id: comment.id,
       deleted: !comment.deleted,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.deleteComment(deleteForm));
   }
 
   handleSaveCommentClick(i: CommentNode) {
     let cv = i.props.node.comment_view;
     let save = cv.saved == undefined ? true : !cv.saved;
-    let form: SaveComment = {
+    let form = new SaveComment({
       comment_id: cv.comment.id,
       save,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
 
     WebSocketService.Instance.send(wsClient.saveComment(form));
 
@@ -979,14 +1139,15 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     this.setState(this.state);
   }
 
-  handleCommentUpvote(i: CommentNodeI, event: any) {
+  handleCommentUpvote(event: any) {
     event.preventDefault();
-    let new_vote = this.state.my_vote == 1 ? 0 : 1;
+    let myVote = this.state.my_vote.unwrapOr(0);
+    let newVote = myVote == 1 ? 0 : 1;
 
-    if (this.state.my_vote == 1) {
+    if (myVote == 1) {
       this.state.score--;
       this.state.upvotes--;
-    } else if (this.state.my_vote == -1) {
+    } else if (myVote == -1) {
       this.state.downvotes--;
       this.state.upvotes++;
       this.state.score += 2;
@@ -995,28 +1156,28 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
       this.state.score++;
     }
 
-    this.state.my_vote = new_vote;
-
-    let form: CreateCommentLike = {
-      comment_id: i.comment_view.comment.id,
-      score: this.state.my_vote,
-      auth: authField(),
-    };
+    this.state.my_vote = Some(newVote);
 
+    let form = new CreateCommentLike({
+      comment_id: this.props.node.comment_view.comment.id,
+      score: newVote,
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.likeComment(form));
     this.setState(this.state);
     setupTippy();
   }
 
-  handleCommentDownvote(i: CommentNodeI, event: any) {
+  handleCommentDownvote(event: any) {
     event.preventDefault();
-    let new_vote = this.state.my_vote == -1 ? 0 : -1;
+    let myVote = this.state.my_vote.unwrapOr(0);
+    let newVote = myVote == -1 ? 0 : -1;
 
-    if (this.state.my_vote == 1) {
+    if (myVote == 1) {
       this.state.score -= 2;
       this.state.upvotes--;
       this.state.downvotes++;
-    } else if (this.state.my_vote == -1) {
+    } else if (myVote == -1) {
       this.state.downvotes--;
       this.state.score++;
     } else {
@@ -1024,26 +1185,50 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
       this.state.score--;
     }
 
-    this.state.my_vote = new_vote;
+    this.state.my_vote = Some(newVote);
 
-    let form: CreateCommentLike = {
-      comment_id: i.comment_view.comment.id,
-      score: this.state.my_vote,
-      auth: authField(),
-    };
+    let form = new CreateCommentLike({
+      comment_id: this.props.node.comment_view.comment.id,
+      score: newVote,
+      auth: auth().unwrap(),
+    });
 
     WebSocketService.Instance.send(wsClient.likeComment(form));
     this.setState(this.state);
     setupTippy();
   }
 
+  handleShowReportDialog(i: CommentNode) {
+    i.state.showReportDialog = !i.state.showReportDialog;
+    i.setState(i.state);
+  }
+
+  handleReportReasonChange(i: CommentNode, event: any) {
+    i.state.reportReason = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleReportSubmit(i: CommentNode) {
+    let comment = i.props.node.comment_view.comment;
+    let form = new CreateCommentReport({
+      comment_id: comment.id,
+      reason: i.state.reportReason,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.createCommentReport(form));
+
+    i.state.showReportDialog = false;
+    i.setState(i.state);
+  }
+
   handleModRemoveShow(i: CommentNode) {
-    i.state.showRemoveDialog = true;
+    i.state.showRemoveDialog = !i.state.showRemoveDialog;
+    i.state.showBanDialog = false;
     i.setState(i.state);
   }
 
   handleModRemoveReasonChange(i: CommentNode, event: any) {
-    i.state.removeReason = event.target.value;
+    i.state.removeReason = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -1054,39 +1239,58 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
   handleModRemoveSubmit(i: CommentNode) {
     let comment = i.props.node.comment_view.comment;
-    let form: RemoveComment = {
+    let form = new RemoveComment({
       comment_id: comment.id,
       removed: !comment.removed,
       reason: i.state.removeReason,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.removeComment(form));
 
     i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
 
+  handleDistinguishClick(i: CommentNode) {
+    let comment = i.props.node.comment_view.comment;
+    let form = new EditComment({
+      comment_id: comment.id,
+      form_id: None, // TODO not sure about this
+      content: None,
+      distinguished: Some(!comment.distinguished),
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.editComment(form));
+    i.setState(i.state);
+  }
+
   isPersonMentionType(
-    item: CommentView | PersonMentionView
+    item: CommentView | PersonMentionView | CommentReplyView
   ): item is PersonMentionView {
     return (item as PersonMentionView).person_mention?.id !== undefined;
   }
 
+  isCommentReplyType(
+    item: CommentView | PersonMentionView | CommentReplyView
+  ): item is CommentReplyView {
+    return (item as CommentReplyView).comment_reply?.id !== undefined;
+  }
+
   handleMarkRead(i: CommentNode) {
     if (i.isPersonMentionType(i.props.node.comment_view)) {
-      let form: MarkPersonMentionAsRead = {
+      let form = new MarkPersonMentionAsRead({
         person_mention_id: i.props.node.comment_view.person_mention.id,
         read: !i.props.node.comment_view.person_mention.read,
-        auth: authField(),
-      };
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(wsClient.markPersonMentionAsRead(form));
-    } else {
-      let form: MarkCommentAsRead = {
-        comment_id: i.props.node.comment_view.comment.id,
-        read: !i.props.node.comment_view.comment.read,
-        auth: authField(),
-      };
-      WebSocketService.Instance.send(wsClient.markCommentAsRead(form));
+    } else if (i.isCommentReplyType(i.props.node.comment_view)) {
+      let form = new MarkCommentReplyAsRead({
+        comment_reply_id: i.props.node.comment_view.comment_reply.id,
+        read: !i.props.node.comment_view.comment_reply.read,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(wsClient.markCommentReplyAsRead(form));
     }
 
     i.state.readLoading = true;
@@ -1094,24 +1298,26 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   }
 
   handleModBanFromCommunityShow(i: CommentNode) {
-    i.state.showBanDialog = !i.state.showBanDialog;
+    i.state.showBanDialog = true;
     i.state.banType = BanType.Community;
+    i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
 
   handleModBanShow(i: CommentNode) {
-    i.state.showBanDialog = !i.state.showBanDialog;
+    i.state.showBanDialog = true;
     i.state.banType = BanType.Site;
+    i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
 
   handleModBanReasonChange(i: CommentNode, event: any) {
-    i.state.banReason = event.target.value;
+    i.state.banReason = Some(event.target.value);
     i.setState(i.state);
   }
 
-  handleModBanExpiresChange(i: CommentNode, event: any) {
-    i.state.banExpires = event.target.value;
+  handleModBanExpireDaysChange(i: CommentNode, event: any) {
+    i.state.banExpireDays = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -1136,15 +1342,15 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
       if (ban == false) {
         i.state.removeData = false;
       }
-      let form: BanFromCommunity = {
+      let form = new BanFromCommunity({
         person_id: cv.creator.id,
         community_id: cv.community.id,
         ban,
-        remove_data: i.state.removeData,
+        remove_data: Some(i.state.removeData),
         reason: i.state.banReason,
-        expires: getUnixTime(i.state.banExpires),
-        auth: authField(),
-      };
+        expires: i.state.banExpireDays.map(futureDaysToUnixTime),
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(wsClient.banFromCommunity(form));
     } else {
       // If its an unban, restore all their data
@@ -1152,14 +1358,14 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
       if (ban == false) {
         i.state.removeData = false;
       }
-      let form: BanPerson = {
+      let form = new BanPerson({
         person_id: cv.creator.id,
         ban,
-        remove_data: i.state.removeData,
+        remove_data: Some(i.state.removeData),
         reason: i.state.banReason,
-        expires: getUnixTime(i.state.banExpires),
-        auth: authField(),
-      };
+        expires: i.state.banExpireDays.map(futureDaysToUnixTime),
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(wsClient.banPerson(form));
     }
 
@@ -1167,6 +1373,48 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     i.setState(i.state);
   }
 
+  handlePurgePersonShow(i: CommentNode) {
+    i.state.showPurgeDialog = true;
+    i.state.purgeType = PurgeType.Person;
+    i.state.showRemoveDialog = false;
+    i.setState(i.state);
+  }
+
+  handlePurgeCommentShow(i: CommentNode) {
+    i.state.showPurgeDialog = true;
+    i.state.purgeType = PurgeType.Comment;
+    i.state.showRemoveDialog = false;
+    i.setState(i.state);
+  }
+
+  handlePurgeReasonChange(i: CommentNode, event: any) {
+    i.state.purgeReason = Some(event.target.value);
+    i.setState(i.state);
+  }
+
+  handlePurgeSubmit(i: CommentNode, event: any) {
+    event.preventDefault();
+
+    if (i.state.purgeType == PurgeType.Person) {
+      let form = new PurgePerson({
+        person_id: i.props.node.comment_view.creator.id,
+        reason: i.state.purgeReason,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(wsClient.purgePerson(form));
+    } else if (i.state.purgeType == PurgeType.Comment) {
+      let form = new PurgeComment({
+        comment_id: i.props.node.comment_view.comment.id,
+        reason: i.state.purgeReason,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(wsClient.purgeComment(form));
+    }
+
+    i.state.purgeLoading = true;
+    i.setState(i.state);
+  }
+
   handleShowConfirmAppointAsMod(i: CommentNode) {
     i.state.showConfirmAppointAsMod = true;
     i.setState(i.state);
@@ -1179,12 +1427,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
   handleAddModToCommunity(i: CommentNode) {
     let cv = i.props.node.comment_view;
-    let form: AddModToCommunity = {
+    let form = new AddModToCommunity({
       person_id: cv.creator.id,
       community_id: cv.community.id,
-      added: !i.isMod,
-      auth: authField(),
-    };
+      added: !isMod(i.props.moderators, cv.creator.id),
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.addModToCommunity(form));
     i.state.showConfirmAppointAsMod = false;
     i.setState(i.state);
@@ -1201,11 +1449,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   }
 
   handleAddAdmin(i: CommentNode) {
-    let form: AddAdmin = {
-      person_id: i.props.node.comment_view.creator.id,
-      added: !i.isAdmin,
-      auth: authField(),
-    };
+    let creatorId = i.props.node.comment_view.creator.id;
+    let form = new AddAdmin({
+      person_id: creatorId,
+      added: !isAdmin(i.props.admins, creatorId),
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.addAdmin(form));
     i.state.showConfirmAppointAsAdmin = false;
     i.setState(i.state);
@@ -1223,11 +1472,11 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
 
   handleTransferCommunity(i: CommentNode) {
     let cv = i.props.node.comment_view;
-    let form: TransferCommunity = {
+    let form = new TransferCommunity({
       community_id: cv.community.id,
       person_id: cv.creator.id,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.transferCommunity(form));
     i.state.showConfirmTransferCommunity = false;
     i.setState(i.state);
@@ -1243,16 +1492,6 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     i.setState(i.state);
   }
 
-  handleTransferSite(i: CommentNode) {
-    let form: TransferSite = {
-      person_id: i.props.node.comment_view.creator.id,
-      auth: authField(),
-    };
-    WebSocketService.Instance.send(wsClient.transferSite(form));
-    i.state.showConfirmTransferSite = false;
-    i.setState(i.state);
-  }
-
   get isCommentNew(): boolean {
     let now = moment.utc().subtract(10, "minutes");
     let then = moment.utc(this.props.node.comment_view.comment.published);
@@ -1276,10 +1515,28 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
     setupTippy();
   }
 
+  handleFetchChildren(i: CommentNode) {
+    let form = new GetComments({
+      post_id: Some(i.props.node.comment_view.post.id),
+      parent_id: Some(i.props.node.comment_view.comment.id),
+      max_depth: Some(commentTreeMaxDepth),
+      page: None,
+      sort: None,
+      limit: Some(999),
+      type_: Some(ListingType.All),
+      community_name: None,
+      community_id: None,
+      saved_only: Some(false),
+      auth: auth(false).ok(),
+    });
+
+    WebSocketService.Instance.send(wsClient.getComments(form));
+  }
+
   get scoreColor() {
-    if (this.state.my_vote == 1) {
+    if (this.state.my_vote.unwrapOr(0) == 1) {
       return "text-info";
-    } else if (this.state.my_vote == -1) {
+    } else if (this.state.my_vote.unwrapOr(0) == -1) {
       return "text-danger";
     } else {
       return "text-muted";
@@ -1289,14 +1546,17 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
   get pointsTippy(): string {
     let points = i18n.t("number_of_points", {
       count: this.state.score,
+      formattedCount: this.state.score,
     });
 
     let upvotes = i18n.t("number_of_upvotes", {
       count: this.state.upvotes,
+      formattedCount: this.state.upvotes,
     });
 
     let downvotes = i18n.t("number_of_downvotes", {
       count: this.state.downvotes,
+      formattedCount: this.state.downvotes,
     });
 
     return `${points} • ${upvotes} • ${downvotes}`;
index 3605358fbeafd52a755f26c12822e1e613506465..f9484c2d4497e15a1d8d18a9beaf8ee1435702de 100644 (file)
@@ -1,13 +1,18 @@
+import { Option } from "@sniptt/monads";
 import { Component } from "inferno";
-import { CommunityModeratorView, PersonViewSafe } from "lemmy-js-client";
-import { CommentNode as CommentNodeI } from "../../interfaces";
+import {
+  CommentNode as CommentNodeI,
+  CommunityModeratorView,
+  PersonViewSafe,
+} from "lemmy-js-client";
+import { CommentViewType } from "../../interfaces";
 import { CommentNode } from "./comment-node";
 
 interface CommentNodesProps {
   nodes: CommentNodeI[];
-  moderators?: CommunityModeratorView[];
-  admins?: PersonViewSafe[];
-  postCreatorId?: number;
+  moderators: Option<CommunityModeratorView[]>;
+  admins: Option<PersonViewSafe[]>;
+  maxCommentsShown: Option<number>;
   noBorder?: boolean;
   noIndent?: boolean;
   viewOnly?: boolean;
@@ -15,7 +20,8 @@ interface CommentNodesProps {
   markable?: boolean;
   showContext?: boolean;
   showCommunity?: boolean;
-  enableDownvotes: boolean;
+  enableDownvotes?: boolean;
+  viewType: CommentViewType;
 }
 
 export class CommentNodes extends Component<CommentNodesProps, any> {
@@ -24,9 +30,13 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
   }
 
   render() {
+    let maxComments = this.props.maxCommentsShown.unwrapOr(
+      this.props.nodes.length
+    );
+
     return (
       <div className="comments">
-        {this.props.nodes.map(node => (
+        {this.props.nodes.slice(0, maxComments).map(node => (
           <CommentNode
             key={node.comment_view.comment.id}
             node={node}
@@ -36,11 +46,11 @@ export class CommentNodes extends Component<CommentNodesProps, any> {
             locked={this.props.locked}
             moderators={this.props.moderators}
             admins={this.props.admins}
-            postCreatorId={this.props.postCreatorId}
             markable={this.props.markable}
             showContext={this.props.showContext}
             showCommunity={this.props.showCommunity}
             enableDownvotes={this.props.enableDownvotes}
+            viewType={this.props.viewType}
           />
         ))}
       </div>
diff --git a/src/shared/components/comment/comment-report.tsx b/src/shared/components/comment/comment-report.tsx
new file mode 100644 (file)
index 0000000..a2d2b10
--- /dev/null
@@ -0,0 +1,117 @@
+import { None } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next-dess";
+import {
+  CommentNode as CommentNodeI,
+  CommentReportView,
+  CommentView,
+  ResolveCommentReport,
+  SubscribedType,
+} from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { CommentViewType } from "../../interfaces";
+import { WebSocketService } from "../../services";
+import { auth, wsClient } from "../../utils";
+import { Icon } from "../common/icon";
+import { PersonListing } from "../person/person-listing";
+import { CommentNode } from "./comment-node";
+
+interface CommentReportProps {
+  report: CommentReportView;
+}
+
+export class CommentReport extends Component<CommentReportProps, any> {
+  constructor(props: any, context: any) {
+    super(props, context);
+  }
+
+  render() {
+    let r = this.props.report;
+    let comment = r.comment;
+    let tippyContent = i18n.t(
+      r.comment_report.resolved ? "unresolve_report" : "resolve_report"
+    );
+
+    // Set the original post data ( a troll could change it )
+    comment.content = r.comment_report.original_comment_text;
+
+    let comment_view: CommentView = {
+      comment,
+      creator: r.comment_creator,
+      post: r.post,
+      community: r.community,
+      creator_banned_from_community: r.creator_banned_from_community,
+      counts: r.counts,
+      subscribed: SubscribedType.NotSubscribed,
+      saved: false,
+      creator_blocked: false,
+      my_vote: r.my_vote,
+    };
+
+    let node: CommentNodeI = {
+      comment_view,
+      children: [],
+      depth: 0,
+    };
+
+    return (
+      <div>
+        <CommentNode
+          node={node}
+          viewType={CommentViewType.Flat}
+          moderators={None}
+          admins={None}
+          enableDownvotes={true}
+          viewOnly={true}
+          showCommunity={true}
+        />
+        <div>
+          {i18n.t("reporter")}: <PersonListing person={r.creator} />
+        </div>
+        <div>
+          {i18n.t("reason")}: {r.comment_report.reason}
+        </div>
+        {r.resolver.match({
+          some: resolver => (
+            <div>
+              {r.comment_report.resolved ? (
+                <T i18nKey="resolved_by">
+                  #
+                  <PersonListing person={resolver} />
+                </T>
+              ) : (
+                <T i18nKey="unresolved_by">
+                  #
+                  <PersonListing person={resolver} />
+                </T>
+              )}
+            </div>
+          ),
+          none: <></>,
+        })}
+        <button
+          className="btn btn-link btn-animate text-muted py-0"
+          onClick={linkEvent(this, this.handleResolveReport)}
+          data-tippy-content={tippyContent}
+          aria-label={tippyContent}
+        >
+          <Icon
+            icon="check"
+            classes={`icon-inline ${
+              r.comment_report.resolved ? "text-success" : "text-danger"
+            }`}
+          />
+        </button>
+      </div>
+    );
+  }
+
+  handleResolveReport(i: CommentReport) {
+    let form = new ResolveCommentReport({
+      report_id: i.props.report.comment_report.id,
+      resolved: !i.props.report.comment_report.resolved,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.resolveCommentReport(form));
+  }
+}
index bca204c9694ba9c3daa3490aa1ee54359ebdb8f4..d3383b5f6f83cf5bc399d4e67be5153f3c85bb1d 100644 (file)
@@ -1,9 +1,10 @@
+import { Option } from "@sniptt/monads";
 import { Component } from "inferno";
 import { PictrsImage } from "./pictrs-image";
 
 interface BannerIconHeaderProps {
-  banner?: string;
-  icon?: string;
+  banner: Option<string>;
+  icon: Option<string>;
 }
 
 export class BannerIconHeader extends Component<BannerIconHeaderProps, any> {
@@ -14,15 +15,21 @@ export class BannerIconHeader extends Component<BannerIconHeaderProps, any> {
   render() {
     return (
       <div class="position-relative mb-2">
-        {this.props.banner && <PictrsImage src={this.props.banner} alt="" />}
-        {this.props.icon && (
-          <PictrsImage
-            src={this.props.icon}
-            iconOverlay
-            pushup={!!this.props.banner}
-            alt=""
-          />
-        )}
+        {this.props.banner.match({
+          some: banner => <PictrsImage src={banner} banner alt="" />,
+          none: <></>,
+        })}
+        {this.props.icon.match({
+          some: icon => (
+            <PictrsImage
+              src={icon}
+              iconOverlay
+              pushup={this.props.banner.isSome()}
+              alt=""
+            />
+          ),
+          none: <></>,
+        })}
       </div>
     );
   }
diff --git a/src/shared/components/common/comment-sort-select.tsx b/src/shared/components/common/comment-sort-select.tsx
new file mode 100644 (file)
index 0000000..b87f266
--- /dev/null
@@ -0,0 +1,70 @@
+import { Component, linkEvent } from "inferno";
+import { CommentSortType } from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { randomStr, relTags, sortingHelpUrl } from "../../utils";
+import { Icon } from "./icon";
+
+interface CommentSortSelectProps {
+  sort: CommentSortType;
+  onChange?(val: CommentSortType): any;
+}
+
+interface CommentSortSelectState {
+  sort: CommentSortType;
+}
+
+export class CommentSortSelect extends Component<
+  CommentSortSelectProps,
+  CommentSortSelectState
+> {
+  private id = `sort-select-${randomStr()}`;
+  private emptyState: CommentSortSelectState = {
+    sort: this.props.sort,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+    this.state = this.emptyState;
+  }
+
+  static getDerivedStateFromProps(props: any): CommentSortSelectState {
+    return {
+      sort: props.sort,
+    };
+  }
+
+  render() {
+    return (
+      <>
+        <select
+          id={this.id}
+          name={this.id}
+          value={this.state.sort}
+          onChange={linkEvent(this, this.handleSortChange)}
+          class="custom-select w-auto mr-2 mb-2"
+          aria-label={i18n.t("sort_type")}
+        >
+          <option disabled aria-hidden="true">
+            {i18n.t("sort_type")}
+          </option>
+          <option value={CommentSortType.Hot}>{i18n.t("hot")}</option>,
+          <option value={CommentSortType.Top}>{i18n.t("top")}</option>,
+          <option value={CommentSortType.New}>{i18n.t("new")}</option>
+          <option value={CommentSortType.Old}>{i18n.t("old")}</option>
+        </select>
+        <a
+          className="text-muted"
+          href={sortingHelpUrl}
+          rel={relTags}
+          title={i18n.t("sorting_help")}
+        >
+          <Icon icon="help-circle" classes="icon-inline" />
+        </a>
+      </>
+    );
+  }
+
+  handleSortChange(i: CommentSortSelect, event: any) {
+    i.props.onChange(event.target.value);
+  }
+}
index 9efed1ff5106e6be838897cd78fb01613a5e7487..1997b4f8cee16e62e191f15558d0444c262d4761 100644 (file)
@@ -1,3 +1,4 @@
+import { Option } from "@sniptt/monads";
 import { Component } from "inferno";
 import { Helmet } from "inferno-helmet";
 import { httpExternalPath } from "../../env";
@@ -6,8 +7,8 @@ import { md } from "../../utils";
 interface HtmlTagsProps {
   title: string;
   path: string;
-  description?: string;
-  image?: string;
+  description: Option<string>;
+  image: Option<string>;
 }
 
 /// Taken from https://metatags.io/
@@ -31,14 +32,17 @@ export class HtmlTags extends Component<HtmlTagsProps, any> {
         <meta property="twitter:card" content="summary_large_image" />
 
         {/* Optional desc and images */}
-        {this.props.description &&
+        {this.props.description.isSome() &&
           ["description", "og:description", "twitter:description"].map(n => (
-            <meta name={n} content={md.renderInline(this.props.description)} />
+            <meta
+              name={n}
+              content={md.renderInline(this.props.description.unwrap())}
+            />
           ))}
 
-        {this.props.image &&
+        {this.props.image.isSome() &&
           ["og:image", "twitter:image"].map(p => (
-            <meta property={p} content={this.props.image} />
+            <meta property={p} content={this.props.image.unwrap()} />
           ))}
       </Helmet>
     );
index 3d103c7cc94c2d6af4dfee0209b6eeaa2d9b22f2..91271cfe539e45b889f38768ad5223c516851eae 100644 (file)
@@ -1,8 +1,12 @@
+import classNames from "classnames";
 import { Component } from "inferno";
+import { i18n } from "../../i18next";
 
 interface IconProps {
   icon: string;
   classes?: string;
+  inline?: boolean;
+  small?: boolean;
 }
 
 export class Icon extends Component<IconProps, any> {
@@ -12,7 +16,12 @@ export class Icon extends Component<IconProps, any> {
 
   render() {
     return (
-      <svg class={`icon ${this.props.classes}`}>
+      <svg
+        class={classNames("icon", this.props.classes, {
+          "icon-inline": this.props.inline,
+          small: this.props.small,
+        })}
+      >
         <use xlinkHref={`#icon-${this.props.icon}`}></use>
         <div class="sr-only">
           <title>{this.props.icon}</title>
@@ -40,3 +49,18 @@ export class Spinner extends Component<SpinnerProps, any> {
     );
   }
 }
+
+export class PurgeWarning extends Component<any, any> {
+  constructor(props: any, context: any) {
+    super(props, context);
+  }
+
+  render() {
+    return (
+      <div class="mt-2 alert alert-danger" role="alert">
+        <Icon icon="alert-triangle" classes="icon-inline mr-2" />
+        {i18n.t("purge_warning")}
+      </div>
+    );
+  }
+}
index a090bc8948a29dea1e9cf12dc2869fede501c13d..5f7a8168f437518a01c78dfaa354ccb4d7547c29 100644 (file)
@@ -1,3 +1,4 @@
+import { Option } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { pictrsUri } from "../../env";
 import { i18n } from "../../i18next";
@@ -7,7 +8,7 @@ import { Icon } from "./icon";
 
 interface ImageUploadFormProps {
   uploadTitle: string;
-  imageSrc: string;
+  imageSrc: Option<string>;
   onUpload(url: string): any;
   onRemove(): any;
   rounded?: boolean;
@@ -36,28 +37,31 @@ export class ImageUploadForm extends Component<
       <form class="d-inline">
         <label
           htmlFor={this.id}
-          class="pointer ml-4 text-muted small font-weight-bold"
+          class="pointer text-muted small font-weight-bold"
         >
-          {!this.props.imageSrc ? (
-            <span class="btn btn-secondary">{this.props.uploadTitle}</span>
-          ) : (
-            <span class="d-inline-block position-relative">
-              <img
-                src={this.props.imageSrc}
-                height={this.props.rounded ? 60 : ""}
-                width={this.props.rounded ? 60 : ""}
-                className={`img-fluid ${
-                  this.props.rounded ? "rounded-circle" : ""
-                }`}
-              />
-              <a
-                onClick={linkEvent(this, this.handleRemoveImage)}
-                aria-label={i18n.t("remove")}
-              >
-                <Icon icon="x" classes="mini-overlay" />
-              </a>
-            </span>
-          )}
+          {this.props.imageSrc.match({
+            some: imageSrc => (
+              <span class="d-inline-block position-relative">
+                <img
+                  src={imageSrc}
+                  height={this.props.rounded ? 60 : ""}
+                  width={this.props.rounded ? 60 : ""}
+                  className={`img-fluid ${
+                    this.props.rounded ? "rounded-circle" : ""
+                  }`}
+                />
+                <a
+                  onClick={linkEvent(this, this.handleRemoveImage)}
+                  aria-label={i18n.t("remove")}
+                >
+                  <Icon icon="x" classes="mini-overlay" />
+                </a>
+              </span>
+            ),
+            none: (
+              <span class="btn btn-secondary">{this.props.uploadTitle}</span>
+            ),
+          })}
         </label>
         <input
           id={this.id}
@@ -65,7 +69,7 @@ export class ImageUploadForm extends Component<
           accept="image/*,video/*"
           name={this.id}
           class="d-none"
-          disabled={!UserService.Instance.myUserInfo}
+          disabled={UserService.Instance.myUserInfo.isNone()}
           onChange={linkEvent(this, this.handleImageUpload)}
         />
       </form>
@@ -104,6 +108,7 @@ export class ImageUploadForm extends Component<
       .catch(error => {
         i.state.loading = false;
         i.setState(i.state);
+        console.error(error);
         toast(error, "danger");
       });
   }
index 4d00c4628a17d6e132201d7961e06348321c157f..0ddd0e9abfca57ce1f2301ac092958be9c55c38d 100644 (file)
@@ -6,7 +6,8 @@ import { randomStr } from "../../utils";
 
 interface ListingTypeSelectProps {
   type_: ListingType;
-  showLocal?: boolean;
+  showLocal: boolean;
+  showSubscribed: boolean;
   onChange?(val: ListingType): any;
 }
 
@@ -33,33 +34,32 @@ export class ListingTypeSelect extends Component<
     return {
       type_: props.type_,
       showLocal: props.showLocal,
+      showSubscribed: props.showSubscribed,
     };
   }
 
   render() {
     return (
       <div class="btn-group btn-group-toggle flex-wrap mb-2">
-        <label
-          title={i18n.t("subscribed_description")}
-          className={`btn btn-outline-secondary 
+        {this.props.showSubscribed && (
+          <label
+            title={i18n.t("subscribed_description")}
+            className={`btn btn-outline-secondary 
             ${this.state.type_ == ListingType.Subscribed && "active"}
-            ${
-              UserService.Instance.myUserInfo == undefined
-                ? "disabled"
-                : "pointer"
-            }
+            ${UserService.Instance.myUserInfo.isNone() ? "disabled" : "pointer"}
           `}
-        >
-          <input
-            id={`${this.id}-subscribed`}
-            type="radio"
-            value={ListingType.Subscribed}
-            checked={this.state.type_ == ListingType.Subscribed}
-            onChange={linkEvent(this, this.handleTypeChange)}
-            disabled={UserService.Instance.myUserInfo == undefined}
-          />
-          {i18n.t("subscribed")}
-        </label>
+          >
+            <input
+              id={`${this.id}-subscribed`}
+              type="radio"
+              value={ListingType.Subscribed}
+              checked={this.state.type_ == ListingType.Subscribed}
+              onChange={linkEvent(this, this.handleTypeChange)}
+              disabled={UserService.Instance.myUserInfo.isNone()}
+            />
+            {i18n.t("subscribed")}
+          </label>
+        )}
         {this.props.showLocal && (
           <label
             title={i18n.t("local_description")}
index d5ed4a92892f0b149b41223c2ef511ca5cbc5c91..e369f8fbb41ba842917bcb12dd5b12855cc4e735 100644 (file)
@@ -1,6 +1,8 @@
+import { None, Option, Some } from "@sniptt/monads";
 import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
+import { toUndefined } from "lemmy-js-client";
 import { pictrsUri } from "../../env";
 import { i18n } from "../../i18next";
 import { UserService } from "../../services";
@@ -10,6 +12,7 @@ import {
   mdToHtml,
   pictrsDeleteToast,
   randomStr,
+  relTags,
   setupTippy,
   setupTribute,
   toast,
@@ -17,22 +20,22 @@ import {
 import { Icon, Spinner } from "./icon";
 
 interface MarkdownTextAreaProps {
-  initialContent: string;
-  finished?: boolean;
-  buttonTitle?: string;
+  initialContent: Option<string>;
+  placeholder: Option<string>;
+  buttonTitle: Option<string>;
+  maxLength: Option<number>;
   replyType?: boolean;
   focus?: boolean;
   disabled?: boolean;
-  maxLength?: number;
-  onSubmit?(msg: { val: string; formId: string }): any;
+  finished?: boolean;
+  hideNavigationWarnings?: boolean;
   onContentChange?(val: string): any;
   onReplyCancel?(): any;
-  hideNavigationWarnings?: boolean;
-  placeholder?: string;
+  onSubmit?(msg: { val: string; formId: string }): any;
 }
 
 interface MarkdownTextAreaState {
-  content: string;
+  content: Option<string>;
   previewMode: boolean;
   loading: boolean;
   imageLoading: boolean;
@@ -67,7 +70,7 @@ export class MarkdownTextArea extends Component<
       autosize(textarea);
       this.tribute.attach(textarea);
       textarea.addEventListener("tribute-replaced", () => {
-        this.state.content = textarea.value;
+        this.state.content = Some(textarea.value);
         this.setState(this.state);
         autosize.update(textarea);
       });
@@ -84,7 +87,7 @@ export class MarkdownTextArea extends Component<
   }
 
   componentDidUpdate() {
-    if (!this.props.hideNavigationWarnings && this.state.content) {
+    if (!this.props.hideNavigationWarnings && this.state.content.isSome()) {
       window.onbeforeunload = () => true;
     } else {
       window.onbeforeunload = undefined;
@@ -95,7 +98,7 @@ export class MarkdownTextArea extends Component<
     if (nextProps.finished) {
       this.state.previewMode = false;
       this.state.loading = false;
-      this.state.content = "";
+      this.state.content = None;
       this.setState(this.state);
       if (this.props.replyType) {
         this.props.onReplyCancel();
@@ -117,7 +120,9 @@ export class MarkdownTextArea extends Component<
     return (
       <form id={this.formId} onSubmit={linkEvent(this, this.handleSubmit)}>
         <Prompt
-          when={!this.props.hideNavigationWarnings && this.state.content}
+          when={
+            !this.props.hideNavigationWarnings && this.state.content.isSome()
+          }
           message={i18n.t("block_leaving")}
         />
         <div class="form-group row">
@@ -125,21 +130,25 @@ export class MarkdownTextArea extends Component<
             <textarea
               id={this.id}
               className={`form-control ${this.state.previewMode && "d-none"}`}
-              value={this.state.content}
+              value={toUndefined(this.state.content)}
               onInput={linkEvent(this, this.handleContentChange)}
               onPaste={linkEvent(this, this.handleImageUploadPaste)}
               required
               disabled={this.props.disabled}
               rows={2}
-              maxLength={this.props.maxLength || 10000}
-              placeholder={this.props.placeholder}
+              maxLength={this.props.maxLength.unwrapOr(10000)}
+              placeholder={toUndefined(this.props.placeholder)}
             />
-            {this.state.previewMode && (
-              <div
-                className="card border-secondary card-body md-div"
-                dangerouslySetInnerHTML={mdToHtml(this.state.content)}
-              />
-            )}
+            {this.state.previewMode &&
+              this.state.content.match({
+                some: content => (
+                  <div
+                    className="card border-secondary card-body md-div"
+                    dangerouslySetInnerHTML={mdToHtml(content)}
+                  />
+                ),
+                none: <></>,
+              })}
           </div>
           <label class="sr-only" htmlFor={this.id}>
             {i18n.t("body")}
@@ -147,19 +156,22 @@ export class MarkdownTextArea extends Component<
         </div>
         <div class="row">
           <div class="col-sm-12 d-flex flex-wrap">
-            {this.props.buttonTitle && (
-              <button
-                type="submit"
-                class="btn btn-sm btn-secondary mr-2"
-                disabled={this.props.disabled || this.state.loading}
-              >
-                {this.state.loading ? (
-                  <Spinner />
-                ) : (
-                  <span>{this.props.buttonTitle}</span>
-                )}
-              </button>
-            )}
+            {this.props.buttonTitle.match({
+              some: buttonTitle => (
+                <button
+                  type="submit"
+                  class="btn btn-sm btn-secondary mr-2"
+                  disabled={this.props.disabled || this.state.loading}
+                >
+                  {this.state.loading ? (
+                    <Spinner />
+                  ) : (
+                    <span>{buttonTitle}</span>
+                  )}
+                </button>
+              ),
+              none: <></>,
+            })}
             {this.props.replyType && (
               <button
                 type="button"
@@ -169,7 +181,7 @@ export class MarkdownTextArea extends Component<
                 {i18n.t("cancel")}
               </button>
             )}
-            {this.state.content && (
+            {this.state.content.isSome() && (
               <button
                 className={`btn btn-sm btn-secondary mr-2 ${
                   this.state.previewMode && "active"
@@ -209,7 +221,7 @@ export class MarkdownTextArea extends Component<
               <label
                 htmlFor={`file-upload-${this.id}`}
                 className={`mb-0 ${
-                  UserService.Instance.myUserInfo && "pointer"
+                  UserService.Instance.myUserInfo.isSome() && "pointer"
                 }`}
                 data-tippy-content={i18n.t("upload_image")}
               >
@@ -225,7 +237,7 @@ export class MarkdownTextArea extends Component<
                 accept="image/*,video/*"
                 name="file"
                 class="d-none"
-                disabled={!UserService.Instance.myUserInfo}
+                disabled={UserService.Instance.myUserInfo.isNone()}
                 onChange={linkEvent(this, this.handleImageUpload)}
               />
             </form>
@@ -297,7 +309,7 @@ export class MarkdownTextArea extends Component<
               href={markdownHelpUrl}
               class="btn btn-sm text-muted font-weight-bold"
               title={i18n.t("formatting_help")}
-              rel="noopener"
+              rel={relTags}
             >
               <Icon icon="help-circle" classes="icon-inline" />
             </a>
@@ -343,9 +355,12 @@ export class MarkdownTextArea extends Component<
           let deleteToken = res.files[0].delete_token;
           let deleteUrl = `${pictrsUri}/delete/${deleteToken}/${hash}`;
           let imageMarkdown = `![](${url})`;
-          let content = i.state.content;
-          content = content ? `${content}\n${imageMarkdown}` : imageMarkdown;
-          i.state.content = content;
+          i.state.content = Some(
+            i.state.content.match({
+              some: content => `${content}\n${imageMarkdown}`,
+              none: imageMarkdown,
+            })
+          );
           i.state.imageLoading = false;
           i.contentChange();
           i.setState(i.state);
@@ -365,18 +380,19 @@ export class MarkdownTextArea extends Component<
       .catch(error => {
         i.state.imageLoading = false;
         i.setState(i.state);
+        console.error(error);
         toast(error, "danger");
       });
   }
 
   contentChange() {
     if (this.props.onContentChange) {
-      this.props.onContentChange(this.state.content);
+      this.props.onContentChange(toUndefined(this.state.content));
     }
   }
 
   handleContentChange(i: MarkdownTextArea, event: any) {
-    i.state.content = event.target.value;
+    i.state.content = Some(event.target.value);
     i.contentChange();
     i.setState(i.state);
   }
@@ -391,7 +407,7 @@ export class MarkdownTextArea extends Component<
     event.preventDefault();
     i.state.loading = true;
     i.setState(i.state);
-    let msg = { val: i.state.content, formId: i.formId };
+    let msg = { val: toUndefined(i.state.content), formId: i.formId };
     i.props.onSubmit(msg);
   }
 
@@ -401,23 +417,28 @@ export class MarkdownTextArea extends Component<
 
   handleInsertLink(i: MarkdownTextArea, event: any) {
     event.preventDefault();
-    if (!i.state.content) {
-      i.state.content = "";
-    }
+
     let textarea: any = document.getElementById(i.id);
     let start: number = textarea.selectionStart;
     let end: number = textarea.selectionEnd;
 
+    if (i.state.content.isNone()) {
+      i.state.content = Some("");
+    }
+
+    let content = i.state.content.unwrap();
+
     if (start !== end) {
-      let selectedText = i.state.content.substring(start, end);
-      i.state.content = `${i.state.content.substring(
-        0,
-        start
-      )}[${selectedText}]()${i.state.content.substring(end)}`;
+      let selectedText = content.substring(start, end);
+      i.state.content = Some(
+        `${content.substring(0, start)}[${selectedText}]()${content.substring(
+          end
+        )}`
+      );
       textarea.focus();
       setTimeout(() => (textarea.selectionEnd = end + 3), 10);
     } else {
-      i.state.content += "[]()";
+      i.state.content = Some(`${content} []()`);
       textarea.focus();
       setTimeout(() => (textarea.selectionEnd -= 1), 10);
     }
@@ -430,7 +451,7 @@ export class MarkdownTextArea extends Component<
   }
 
   simpleBeginningofLine(chars: string) {
-    this.simpleSurroundBeforeAfter(`${chars} `, "", "");
+    this.simpleSurroundBeforeAfter(`${chars}`, "", "");
   }
 
   simpleSurroundBeforeAfter(
@@ -438,26 +459,45 @@ export class MarkdownTextArea extends Component<
     afterChars: string,
     emptyChars = "___"
   ) {
-    if (!this.state.content) {
-      this.state.content = "";
+    if (this.state.content.isNone()) {
+      this.state.content = Some("");
     }
     let textarea: any = document.getElementById(this.id);
     let start: number = textarea.selectionStart;
     let end: number = textarea.selectionEnd;
 
+    let content = this.state.content.unwrap();
+
     if (start !== end) {
-      let selectedText = this.state.content.substring(start, end);
-      this.state.content = `${this.state.content.substring(
-        0,
-        start
-      )}${beforeChars}${selectedText}${afterChars}${this.state.content.substring(
-        end
-      )}`;
+      let selectedText = content.substring(start, end);
+      this.state.content = Some(
+        `${content.substring(
+          0,
+          start
+        )}${beforeChars}${selectedText}${afterChars}${content.substring(end)}`
+      );
     } else {
-      this.state.content += `${beforeChars}${emptyChars}${afterChars}`;
+      this.state.content = Some(
+        `${content}${beforeChars}${emptyChars}${afterChars}`
+      );
     }
     this.contentChange();
     this.setState(this.state);
+
+    textarea.focus();
+
+    if (start !== end) {
+      textarea.setSelectionRange(
+        start + beforeChars.length,
+        end + afterChars.length
+      );
+    } else {
+      textarea.setSelectionRange(
+        start + beforeChars.length,
+        end + emptyChars.length + afterChars.length
+      );
+    }
+
     setTimeout(() => {
       autosize.update(textarea);
     }, 10);
@@ -513,10 +553,10 @@ export class MarkdownTextArea extends Component<
   }
 
   simpleInsert(chars: string) {
-    if (!this.state.content) {
-      this.state.content = `${chars} `;
+    if (this.state.content.isNone()) {
+      this.state.content = Some(`${chars} `);
     } else {
-      this.state.content += `\n${chars} `;
+      this.state.content = Some(`${this.state.content.unwrap()}\n${chars} `);
     }
 
     let textarea: any = document.getElementById(this.id);
@@ -544,12 +584,12 @@ export class MarkdownTextArea extends Component<
           .split("\n")
           .map(t => `> ${t}`)
           .join("\n") + "\n\n";
-      if (this.state.content == null) {
-        this.state.content = "";
+      if (this.state.content.isNone()) {
+        this.state.content = Some("");
       } else {
-        this.state.content += "\n";
+        this.state.content = Some(`${this.state.content.unwrap()}\n`);
       }
-      this.state.content += quotedText;
+      this.state.content = Some(`${this.state.content.unwrap()}${quotedText}`);
       this.contentChange();
       this.setState(this.state);
       // Not sure why this needs a delay
@@ -561,6 +601,8 @@ export class MarkdownTextArea extends Component<
     let textarea: any = document.getElementById(this.id);
     let start: number = textarea.selectionStart;
     let end: number = textarea.selectionEnd;
-    return start !== end ? this.state.content.substring(start, end) : "";
+    return start !== end
+      ? this.state.content.unwrap().substring(start, end)
+      : "";
   }
 }
index 20623932f68d77900404e2961cb28ca5d39f12d3..3d3c5485c9058176b276477a34a2d149fb1ef9a6 100644 (file)
@@ -1,15 +1,13 @@
+import { Option } from "@sniptt/monads";
 import { Component } from "inferno";
 import moment from "moment";
 import { i18n } from "../../i18next";
-import { capitalizeFirstLetter, getMomentLanguage } from "../../utils";
+import { capitalizeFirstLetter, getLanguages } from "../../utils";
 import { Icon } from "./icon";
 
 interface MomentTimeProps {
-  data: {
-    published?: string;
-    when_?: string;
-    updated?: string;
-  };
+  published: string;
+  updated: Option<string>;
   showAgo?: boolean;
   ignoreUpdated?: boolean;
 }
@@ -18,32 +16,38 @@ export class MomentTime extends Component<MomentTimeProps, any> {
   constructor(props: any, context: any) {
     super(props, context);
 
-    let lang = getMomentLanguage();
+    let lang = getLanguages();
 
     moment.locale(lang);
   }
 
+  createdAndModifiedTimes() {
+    return `${capitalizeFirstLetter(i18n.t("created"))}: ${this.format(
+      this.props.published
+    )}\n\n\n${
+      this.props.updated.isSome() && capitalizeFirstLetter(i18n.t("modified"))
+    } ${this.format(this.props.updated.unwrap())}`;
+  }
+
   render() {
-    if (!this.props.ignoreUpdated && this.props.data.updated) {
+    if (!this.props.ignoreUpdated && this.props.updated.isSome()) {
       return (
         <span
-          data-tippy-content={`${capitalizeFirstLetter(
-            i18n.t("modified")
-          )} ${this.format(this.props.data.updated)}`}
+          data-tippy-content={this.createdAndModifiedTimes()}
           className="font-italics pointer unselectable"
         >
           <Icon icon="edit-2" classes="icon-inline mr-1" />
-          {moment.utc(this.props.data.updated).fromNow(!this.props.showAgo)}
+          {moment.utc(this.props.updated.unwrap()).fromNow(!this.props.showAgo)}
         </span>
       );
     } else {
-      let str = this.props.data.published || this.props.data.when_;
+      let published = this.props.published;
       return (
         <span
           className="pointer unselectable"
-          data-tippy-content={this.format(str)}
+          data-tippy-content={this.format(published)}
         >
-          {moment.utc(str).fromNow(!this.props.showAgo)}
+          {moment.utc(published).fromNow(!this.props.showAgo)}
         </span>
       );
     }
index 5c8abb98bbdd128d55073a33a9a0a00807905b04..4f3ddc05f9ae80a4f4b3763bbfe65f2ec8794403 100644 (file)
@@ -1,13 +1,14 @@
+import classNames from "classnames";
 import { Component } from "inferno";
 
 const iconThumbnailSize = 96;
 const thumbnailSize = 256;
-const maxImageSize = 3000;
 
 interface PictrsImageProps {
   src: string;
   alt?: string;
   icon?: boolean;
+  banner?: boolean;
   thumbnail?: boolean;
   nsfw?: boolean;
   iconOverlay?: boolean;
@@ -23,23 +24,24 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
     return (
       <picture>
         <source srcSet={this.src("webp")} type="image/webp" />
+        <source srcSet={this.props.src} />
         <source srcSet={this.src("jpg")} type="image/jpeg" />
         <img
-          src={this.src("jpg")}
+          src={this.props.src}
           alt={this.alt()}
           loading="lazy"
-          className={`
-        ${!this.props.icon && !this.props.iconOverlay && "img-fluid "}
-        ${
-          this.props.thumbnail && !this.props.icon
-            ? "thumbnail rounded "
-            : "img-expanded "
-        }
-        ${this.props.thumbnail && this.props.nsfw && "img-blur "}
-        ${this.props.icon && "rounded-circle img-icon mr-2 "}
-        ${this.props.iconOverlay && "ml-2 mb-0 rounded-circle avatar-overlay "}
-        ${this.props.pushup && "avatar-pushup "}
-        `}
+          className={classNames({
+            "img-fluid": !this.props.icon && !this.props.iconOverlay,
+            banner: this.props.banner,
+            "thumbnail rounded":
+              this.props.thumbnail && !this.props.icon && !this.props.banner,
+            "img-expanded slight-radius":
+              !this.props.thumbnail && !this.props.icon,
+            "img-blur": this.props.thumbnail && this.props.nsfw,
+            "rounded-circle img-icon mr-2": this.props.icon,
+            "ml-2 mb-0 rounded-circle avatar-overlay": this.props.iconOverlay,
+            "avatar-pushup": this.props.pushup,
+          })}
         />
       </picture>
     );
@@ -65,12 +67,10 @@ export class PictrsImage extends Component<PictrsImageProps, any> {
       params["thumbnail"] = thumbnailSize;
     } else if (this.props.icon) {
       params["thumbnail"] = iconThumbnailSize;
-    } else {
-      params["thumbnail"] = maxImageSize;
     }
 
-    let paramsStr = `?${new URLSearchParams(params).toString()}`;
-    let out = `${host}/pictrs/image/${path}${paramsStr}`;
+    let paramsStr = new URLSearchParams(params).toString();
+    let out = `${host}/pictrs/image/${path}?${paramsStr}`;
 
     return out;
   }
diff --git a/src/shared/components/common/registration-application.tsx b/src/shared/components/common/registration-application.tsx
new file mode 100644 (file)
index 0000000..f3c2cf5
--- /dev/null
@@ -0,0 +1,163 @@
+import { None, Option, Some } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next-dess";
+import {
+  ApproveRegistrationApplication,
+  RegistrationApplicationView,
+} from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
+import { auth, mdToHtml, wsClient } from "../../utils";
+import { PersonListing } from "../person/person-listing";
+import { MarkdownTextArea } from "./markdown-textarea";
+import { MomentTime } from "./moment-time";
+
+interface RegistrationApplicationProps {
+  application: RegistrationApplicationView;
+}
+
+interface RegistrationApplicationState {
+  denyReason: Option<string>;
+  denyExpanded: boolean;
+}
+
+export class RegistrationApplication extends Component<
+  RegistrationApplicationProps,
+  RegistrationApplicationState
+> {
+  private emptyState: RegistrationApplicationState = {
+    denyReason: this.props.application.registration_application.deny_reason,
+    denyExpanded: false,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+
+    this.state = this.emptyState;
+    this.handleDenyReasonChange = this.handleDenyReasonChange.bind(this);
+  }
+
+  render() {
+    let a = this.props.application;
+    let ra = this.props.application.registration_application;
+    let accepted = a.creator_local_user.accepted_application;
+
+    return (
+      <div>
+        <div>
+          {i18n.t("applicant")}: <PersonListing person={a.creator} />
+        </div>
+        <div>
+          {i18n.t("created")}:{" "}
+          <MomentTime showAgo published={ra.published} updated={None} />
+        </div>
+        <div>{i18n.t("answer")}:</div>
+        <div className="md-div" dangerouslySetInnerHTML={mdToHtml(ra.answer)} />
+
+        {a.admin.match({
+          some: admin => (
+            <div>
+              {accepted ? (
+                <T i18nKey="approved_by">
+                  #
+                  <PersonListing person={admin} />
+                </T>
+              ) : (
+                <div>
+                  <T i18nKey="denied_by">
+                    #
+                    <PersonListing person={admin} />
+                  </T>
+                  {ra.deny_reason.match({
+                    some: deny_reason => (
+                      <div>
+                        {i18n.t("deny_reason")}:{" "}
+                        <div
+                          className="md-div d-inline-flex"
+                          dangerouslySetInnerHTML={mdToHtml(deny_reason)}
+                        />
+                      </div>
+                    ),
+                    none: <></>,
+                  })}
+                </div>
+              )}
+            </div>
+          ),
+          none: <></>,
+        })}
+
+        {this.state.denyExpanded && (
+          <div class="form-group row">
+            <label class="col-sm-2 col-form-label">
+              {i18n.t("deny_reason")}
+            </label>
+            <div class="col-sm-10">
+              <MarkdownTextArea
+                initialContent={this.state.denyReason}
+                onContentChange={this.handleDenyReasonChange}
+                placeholder={None}
+                buttonTitle={None}
+                maxLength={None}
+                hideNavigationWarnings
+              />
+            </div>
+          </div>
+        )}
+        {(ra.admin_id.isNone() || (ra.admin_id.isSome() && !accepted)) && (
+          <button
+            className="btn btn-secondary mr-2 my-2"
+            onClick={linkEvent(this, this.handleApprove)}
+            aria-label={i18n.t("approve")}
+          >
+            {i18n.t("approve")}
+          </button>
+        )}
+        {(ra.admin_id.isNone() || (ra.admin_id.isSome() && accepted)) && (
+          <button
+            className="btn btn-secondary mr-2"
+            onClick={linkEvent(this, this.handleDeny)}
+            aria-label={i18n.t("deny")}
+          >
+            {i18n.t("deny")}
+          </button>
+        )}
+      </div>
+    );
+  }
+
+  handleApprove(i: RegistrationApplication) {
+    i.setState({ denyExpanded: false });
+    let form = new ApproveRegistrationApplication({
+      id: i.props.application.registration_application.id,
+      deny_reason: None,
+      approve: true,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(
+      wsClient.approveRegistrationApplication(form)
+    );
+  }
+
+  handleDeny(i: RegistrationApplication) {
+    if (i.state.denyExpanded) {
+      i.setState({ denyExpanded: false });
+      let form = new ApproveRegistrationApplication({
+        id: i.props.application.registration_application.id,
+        approve: false,
+        deny_reason: i.state.denyReason,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(
+        wsClient.approveRegistrationApplication(form)
+      );
+    } else {
+      i.setState({ denyExpanded: true });
+    }
+  }
+
+  handleDenyReasonChange(val: string) {
+    this.state.denyReason = Some(val);
+    this.setState(this.state);
+  }
+}
index 9504756e9bdb34268ea11de86ad921e2c377f8e3..3f815f5b0eb6e728ff9fea9ad01544fd59fd4505 100644 (file)
@@ -1,7 +1,7 @@
 import { Component, linkEvent } from "inferno";
 import { SortType } from "lemmy-js-client";
 import { i18n } from "../../i18next";
-import { randomStr, sortingHelpUrl } from "../../utils";
+import { randomStr, relTags, sortingHelpUrl } from "../../utils";
 import { Icon } from "./icon";
 
 interface SortSelectProps {
@@ -51,6 +51,7 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
             <option value={SortType.Active}>{i18n.t("active")}</option>,
           ]}
           <option value={SortType.New}>{i18n.t("new")}</option>
+          <option value={SortType.Old}>{i18n.t("old")}</option>
           {!this.props.hideMostComments && [
             <option value={SortType.MostComments}>
               {i18n.t("most_comments")}
@@ -71,7 +72,7 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
         <a
           className="text-muted"
           href={sortingHelpUrl}
-          rel="noopener"
+          rel={relTags}
           title={i18n.t("sorting_help")}
         >
           <Icon icon="help-circle" classes="icon-inline" />
index f94bc551ee3164cd023361a41e751fbc9babbeaf..03791d1bec58cc9977f1e49890236f37a1b65f65 100644 (file)
@@ -12,6 +12,80 @@ export const SYMBOLS = (
     xmlnsXlink="http://www.w3.org/1999/xlink"
   >
     <defs>
+      <symbol
+        id="icon-fedilink"
+        viewBox="0 0 196.52 196.52"
+        xmlns="http://www.w3.org/2000/svg"
+      >
+        <g color="#000" font-weight="400" font-family="sans-serif">
+          <path
+            d="M47.924 72.797a18.228 18.228 0 0 1-7.796 7.76l42.799 42.965 10.318-5.23zm56.453 56.67l-10.319 5.23 21.686 21.77a18.228 18.228 0 0 1 7.798-7.76z"
+            overflow="visible"
+            fill="#a730b8"
+          />
+          <path
+            d="M153.894 89.797l-24.23 12.28 1.787 11.427 27.415-13.895a18.228 18.228 0 0 1-4.972-9.812zm-38.295 19.408l-57.29 29.034a18.228 18.228 0 0 1 4.973 9.813l54.103-27.42z"
+            overflow="visible"
+            fill="#5496be"
+          />
+          <path
+            d="M97.175 37.687L69.53 91.654l8.162 8.193 29.269-57.138a18.228 18.228 0 0 1-9.787-5.022zM62.34 105.69L48.34 133.025a18.228 18.228 0 0 1 9.786 5.022l12.378-24.164z"
+            overflow="visible"
+            fill="#ce3d1a"
+          />
+          <path
+            d="M39.89 80.676a18.228 18.228 0 0 1-9.105 1.904 18.228 18.228 0 0 1-1.76-.184l8.176 52.298a18.228 18.228 0 0 1 9.106-1.904 18.228 18.228 0 0 1 1.759.184z"
+            overflow="visible"
+            fill="#d0188f"
+          />
+          <path
+            d="M63.326 148.31a18.228 18.228 0 0 1 .19 3.672 18.228 18.228 0 0 1-1.922 7.192l52.289 8.39a18.228 18.228 0 0 1-.191-3.672 18.228 18.228 0 0 1 1.923-7.19z"
+            overflow="visible"
+            fill="#5b36e9"
+          />
+          <path
+            d="M159.05 99.8l-24.135 47.118a18.228 18.228 0 0 1 9.788 5.023l24.134-47.117a18.228 18.228 0 0 1-9.787-5.023z"
+            overflow="visible"
+            fill="#30b873"
+          />
+          <path
+            d="M126.133 33.16a18.228 18.228 0 0 1-7.798 7.761l37.377 37.52a18.228 18.228 0 0 1 7.797-7.76z"
+            overflow="visible"
+            fill="#ebe305"
+          />
+          <path
+            d="M92.019 27.684L44.77 51.628a18.228 18.228 0 0 1 4.973 9.812L96.99 37.495a18.228 18.228 0 0 1-4.971-9.811z"
+            overflow="visible"
+            fill="#f47601"
+          />
+          <path
+            d="M118.25 40.964a18.228 18.228 0 0 1-9.257 1.98 18.228 18.228 0 0 1-1.595-.167l4.185 26.8 11.42 1.832zm-4.234 44.193l9.895 63.363a18.228 18.228 0 0 1 8.973-1.837 18.228 18.228 0 0 1 1.907.21l-9.355-59.904z"
+            overflow="visible"
+            fill="#57c115"
+          />
+          <path
+            d="M49.776 61.641a18.228 18.228 0 0 1 .2 3.73 18.228 18.228 0 0 1-1.894 7.139l26.82 4.308 5.272-10.295zm45.968 7.382L90.472 79.32l63.371 10.177a18.228 18.228 0 0 1-.184-3.63 18.228 18.228 0 0 1 1.945-7.229z"
+            overflow="visible"
+            fill="#dbb210"
+          />
+        </g>
+        <g transform="rotate(3.118 600.365 106.46)" fill-opacity=".996">
+          <circle cx="106.266" cy="51.536" r="16.571" fill="#ffca00" />
+          <circle cx="171.428" cy="110.193" r="16.571" fill="#64ff00" />
+          <circle cx="135.764" cy="190.277" r="16.571" fill="#00a3ff" />
+          <circle cx="48.559" cy="181.114" r="16.571" fill="#9500ff" />
+          <circle cx="30.329" cy="95.367" r="16.571" fill="red" />
+        </g>
+      </symbol>
+      <symbol id="icon-clipboard" viewBox="0 0 24 24">
+        <path d="M7 5c0 0.552 0.225 1.053 0.586 1.414s0.862 0.586 1.414 0.586h6c0.552 0 1.053-0.225 1.414-0.586s0.586-0.862 0.586-1.414h1c0.276 0 0.525 0.111 0.707 0.293s0.293 0.431 0.293 0.707v14c0 0.276-0.111 0.525-0.293 0.707s-0.431 0.293-0.707 0.293h-12c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293zM9 1c-0.552 0-1.053 0.225-1.414 0.586s-0.586 0.862-0.586 1.414h-1c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h12c0.828 0 1.58-0.337 2.121-0.879s0.879-1.293 0.879-2.121v-14c0-0.828-0.337-1.58-0.879-2.121s-1.293-0.879-2.121-0.879h-1c0-0.552-0.225-1.053-0.586-1.414s-0.862-0.586-1.414-0.586zM9 3h6v2h-6z"></path>
+      </symbol>
+      <symbol id="icon-shield" viewBox="0 0 24 24">
+        <path d="M12 20.862c-1.184-0.672-4.42-2.695-6.050-5.549-0.079-0.138-0.153-0.276-0.223-0.417-0.456-0.911-0.727-1.878-0.727-2.896v-6.307l7-2.625 7 2.625v6.307c0 1.018-0.271 1.985-0.726 2.897-0.070 0.14-0.145 0.279-0.223 0.417-1.631 2.854-4.867 4.876-6.050 5.549zM12.447 22.894c0 0 4.989-2.475 7.34-6.589 0.096-0.168 0.188-0.34 0.276-0.515 0.568-1.135 0.937-2.408 0.937-3.79v-7c0-0.426-0.267-0.79-0.649-0.936l-8-3c-0.236-0.089-0.485-0.082-0.702 0l-8 3c-0.399 0.149-0.646 0.527-0.649 0.936v7c0 1.382 0.369 2.655 0.938 3.791 0.087 0.175 0.179 0.346 0.276 0.515 2.351 4.114 7.34 6.589 7.34 6.589 0.292 0.146 0.62 0.136 0.894 0z"></path>
+      </symbol>
+      <symbol id="icon-flag" viewBox="0 0 24 24">
+        <path d="M5 13.397v-9.859c0.44-0.218 1.365-0.538 3-0.538 1.281 0 2.361 0.421 3.629 0.928 1.232 0.493 2.652 1.072 4.371 1.072 1.298 0 2.278-0.175 3-0.397v9.859c-0.44 0.218-1.365 0.538-3 0.538-1.281 0-2.361-0.421-3.629-0.928-1.232-0.493-2.652-1.072-4.371-1.072-1.298 0-2.278 0.175-3 0.397zM5 22v-6.462c0.44-0.218 1.365-0.538 3-0.538 1.281 0 2.361 0.421 3.629 0.928 1.232 0.493 2.652 1.072 4.371 1.072 3.247 0 4.507-1.093 4.707-1.293 0.195-0.195 0.293-0.451 0.293-0.707v-12c0-0.552-0.448-1-1-1-0.265 0-0.506 0.103-0.685 0.272-0.096 0.078-0.984 0.728-3.315 0.728-1.281 0-2.361-0.421-3.629-0.928-1.232-0.493-2.652-1.072-4.371-1.072-3.247 0-4.507 1.093-4.707 1.293-0.195 0.195-0.293 0.451-0.293 0.707v19c0 0.552 0.448 1 1 1s1-0.448 1-1z"></path>
+      </symbol>
       <symbol id="icon-log-out" viewBox="0 0 24 24">
         <path d="M9 20h-4c-0.276 0-0.525-0.111-0.707-0.293s-0.293-0.431-0.293-0.707v-14c0-0.276 0.111-0.525 0.293-0.707s0.431-0.293 0.707-0.293h4c0.552 0 1-0.448 1-1s-0.448-1-1-1h-4c-0.828 0-1.58 0.337-2.121 0.879s-0.879 1.293-0.879 2.121v14c0 0.828 0.337 1.58 0.879 2.121s1.293 0.879 2.121 0.879h4c0.552 0 1-0.448 1-1s-0.448-1-1-1zM18.586 11h-9.586c-0.552 0-1 0.448-1 1s0.448 1 1 1h9.586l-3.293 3.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5-5c0.092-0.092 0.166-0.202 0.217-0.324 0.15-0.362 0.078-0.795-0.217-1.090l-5-5c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"></path>
       </symbol>
index aa34be35a9bf527190e89c1813129afcd749c693..db17084a3e56ebd0e74f8cb41055d234124e358a 100644 (file)
@@ -1,32 +1,33 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import {
   CommunityResponse,
-  CommunityView,
   FollowCommunity,
+  GetSiteResponse,
   ListCommunities,
   ListCommunitiesResponse,
   ListingType,
-  SiteView,
   SortType,
+  SubscribedType,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { InitialFetchRequest } from "shared/interfaces";
 import { i18n } from "../../i18next";
 import { WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   getListingTypeFromPropsNoDefault,
   getPageFromProps,
   isBrowser,
+  numToSI,
   setIsoData,
-  setOptionalAuth,
   showLocal,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
@@ -34,13 +35,13 @@ import { ListingTypeSelect } from "../common/listing-type-select";
 import { Paginator } from "../common/paginator";
 import { CommunityLink } from "./community-link";
 
-const communityLimit = 100;
+const communityLimit = 50;
 
 interface CommunitiesState {
-  communities: CommunityView[];
+  listCommunitiesResponse: Option<ListCommunitiesResponse>;
   page: number;
   loading: boolean;
-  site_view: SiteView;
+  siteRes: GetSiteResponse;
   searchText: string;
   listingType: ListingType;
 }
@@ -52,13 +53,13 @@ interface CommunitiesProps {
 
 export class Communities extends Component<any, CommunitiesState> {
   private subscription: Subscription;
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(this.context, ListCommunitiesResponse);
   private emptyState: CommunitiesState = {
-    communities: [],
+    listCommunitiesResponse: None,
     loading: true,
     page: getPageFromProps(this.props),
     listingType: getListingTypeFromPropsNoDefault(this.props),
-    site_view: this.isoData.site_res.site_view,
+    siteRes: this.isoData.site_res,
     searchText: "",
   };
 
@@ -73,7 +74,8 @@ export class Communities extends Component<any, CommunitiesState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.communities = this.isoData.routeData[0].communities;
+      let listRes = Some(this.isoData.routeData[0] as ListCommunitiesResponse);
+      this.state.listCommunitiesResponse = listRes;
       this.state.loading = false;
     } else {
       this.refetch();
@@ -104,7 +106,10 @@ export class Communities extends Component<any, CommunitiesState> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("communities")} - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("communities")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
@@ -113,6 +118,8 @@ export class Communities extends Component<any, CommunitiesState> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         {this.state.loading ? (
           <h5>
@@ -127,6 +134,7 @@ export class Communities extends Component<any, CommunitiesState> {
                   <ListingTypeSelect
                     type_={this.state.listingType}
                     showLocal={showLocal(this.isoData)}
+                    showSubscribed
                     onChange={this.handleListingTypeChange}
                   />
                 </span>
@@ -155,44 +163,57 @@ export class Communities extends Component<any, CommunitiesState> {
                   </tr>
                 </thead>
                 <tbody>
-                  {this.state.communities.map(cv => (
-                    <tr>
-                      <td>
-                        <CommunityLink community={cv.community} />
-                      </td>
-                      <td class="text-right">{cv.counts.subscribers}</td>
-                      <td class="text-right">{cv.counts.users_active_month}</td>
-                      <td class="text-right d-none d-lg-table-cell">
-                        {cv.counts.posts}
-                      </td>
-                      <td class="text-right d-none d-lg-table-cell">
-                        {cv.counts.comments}
-                      </td>
-                      <td class="text-right">
-                        {cv.subscribed ? (
-                          <button
-                            class="btn btn-link d-inline-block"
-                            onClick={linkEvent(
-                              cv.community.id,
-                              this.handleUnsubscribe
-                            )}
-                          >
-                            {i18n.t("unsubscribe")}
-                          </button>
-                        ) : (
-                          <button
-                            class="btn btn-link d-inline-block"
-                            onClick={linkEvent(
-                              cv.community.id,
-                              this.handleSubscribe
-                            )}
-                          >
-                            {i18n.t("subscribe")}
-                          </button>
-                        )}
-                      </td>
-                    </tr>
-                  ))}
+                  {this.state.listCommunitiesResponse
+                    .map(l => l.communities)
+                    .unwrapOr([])
+                    .map(cv => (
+                      <tr>
+                        <td>
+                          <CommunityLink community={cv.community} />
+                        </td>
+                        <td class="text-right">
+                          {numToSI(cv.counts.subscribers)}
+                        </td>
+                        <td class="text-right">
+                          {numToSI(cv.counts.users_active_month)}
+                        </td>
+                        <td class="text-right d-none d-lg-table-cell">
+                          {numToSI(cv.counts.posts)}
+                        </td>
+                        <td class="text-right d-none d-lg-table-cell">
+                          {numToSI(cv.counts.comments)}
+                        </td>
+                        <td class="text-right">
+                          {cv.subscribed == SubscribedType.Subscribed && (
+                            <button
+                              class="btn btn-link d-inline-block"
+                              onClick={linkEvent(
+                                cv.community.id,
+                                this.handleUnsubscribe
+                              )}
+                            >
+                              {i18n.t("unsubscribe")}
+                            </button>
+                          )}
+                          {cv.subscribed == SubscribedType.NotSubscribed && (
+                            <button
+                              class="btn btn-link d-inline-block"
+                              onClick={linkEvent(
+                                cv.community.id,
+                                this.handleSubscribe
+                              )}
+                            >
+                              {i18n.t("subscribe")}
+                            </button>
+                          )}
+                          {cv.subscribed == SubscribedType.Pending && (
+                            <div class="text-warning d-inline-block">
+                              {i18n.t("subscribe_pending")}
+                            </div>
+                          )}
+                        </td>
+                      </tr>
+                    ))}
                 </tbody>
               </table>
             </div>
@@ -252,20 +273,20 @@ export class Communities extends Component<any, CommunitiesState> {
   }
 
   handleUnsubscribe(communityId: number) {
-    let form: FollowCommunity = {
+    let form = new FollowCommunity({
       community_id: communityId,
       follow: false,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.followCommunity(form));
   }
 
   handleSubscribe(communityId: number) {
-    let form: FollowCommunity = {
+    let form = new FollowCommunity({
       community_id: communityId,
       follow: true,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.followCommunity(form));
   }
 
@@ -281,13 +302,13 @@ export class Communities extends Component<any, CommunitiesState> {
   }
 
   refetch() {
-    let listCommunitiesForm: ListCommunities = {
-      type_: this.state.listingType,
-      sort: SortType.TopMonth,
-      limit: communityLimit,
-      page: this.state.page,
-      auth: authField(false),
-    };
+    let listCommunitiesForm = new ListCommunities({
+      type_: Some(this.state.listingType),
+      sort: Some(SortType.TopMonth),
+      limit: Some(communityLimit),
+      page: Some(this.state.page),
+      auth: auth(false).ok(),
+    });
 
     WebSocketService.Instance.send(
       wsClient.listCommunities(listCommunitiesForm)
@@ -296,17 +317,17 @@ export class Communities extends Component<any, CommunitiesState> {
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
     let pathSplit = req.path.split("/");
-    let type_: ListingType = pathSplit[3]
-      ? ListingType[pathSplit[3]]
-      : ListingType.Local;
-    let page = pathSplit[5] ? Number(pathSplit[5]) : 1;
-    let listCommunitiesForm: ListCommunities = {
+    let type_: Option<ListingType> = Some(
+      pathSplit[3] ? ListingType[pathSplit[3]] : ListingType.Local
+    );
+    let page = Some(pathSplit[5] ? Number(pathSplit[5]) : 1);
+    let listCommunitiesForm = new ListCommunities({
       type_,
-      sort: SortType.TopMonth,
-      limit: communityLimit,
+      sort: Some(SortType.TopMonth),
+      limit: Some(communityLimit),
       page,
-    };
-    setOptionalAuth(listCommunitiesForm, req.auth);
+      auth: req.auth,
+    });
 
     return [req.client.listCommunities(listCommunitiesForm)];
   }
@@ -318,18 +339,26 @@ export class Communities extends Component<any, CommunitiesState> {
       toast(i18n.t(msg.error), "danger");
       return;
     } else if (op == UserOperation.ListCommunities) {
-      let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
-      this.state.communities = data.communities;
+      let data = wsJsonToRes<ListCommunitiesResponse>(
+        msg,
+        ListCommunitiesResponse
+      );
+      this.state.listCommunitiesResponse = Some(data);
       this.state.loading = false;
       window.scrollTo(0, 0);
       this.setState(this.state);
     } else if (op == UserOperation.FollowCommunity) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
-      let found = this.state.communities.find(
-        c => c.community.id == data.community_view.community.id
-      );
-      found.subscribed = data.community_view.subscribed;
-      found.counts.subscribers = data.community_view.counts.subscribers;
+      let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
+      this.state.listCommunitiesResponse.match({
+        some: res => {
+          let found = res.communities.find(
+            c => c.community.id == data.community_view.community.id
+          );
+          found.subscribed = data.community_view.subscribed;
+          found.counts.subscribers = data.community_view.counts.subscribers;
+        },
+        none: void 0,
+      });
       this.setState(this.state);
     }
   }
index 45cd5ec4f81a73a3206b3fc3dc4bc9827581e512..cce144bf07b2de1b2f264cfe73c90af626d19a73 100644 (file)
@@ -1,3 +1,4 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
 import {
@@ -5,31 +6,31 @@ import {
   CommunityView,
   CreateCommunity,
   EditCommunity,
+  toUndefined,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
   randomStr,
-  toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { Icon, Spinner } from "../common/icon";
 import { ImageUploadForm } from "../common/image-upload-form";
 import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface CommunityFormProps {
-  community_view?: CommunityView; // If a community is given, that means this is an edit
+  community_view: Option<CommunityView>; // If a community is given, that means this is an edit
   onCancel?(): any;
   onCreate?(community: CommunityView): any;
   onEdit?(community: CommunityView): any;
-  enableNsfw: boolean;
+  enableNsfw?: boolean;
 }
 
 interface CommunityFormState {
@@ -45,14 +46,16 @@ export class CommunityForm extends Component<
   private subscription: Subscription;
 
   private emptyState: CommunityFormState = {
-    communityForm: {
-      name: null,
-      title: null,
-      nsfw: false,
-      icon: null,
-      banner: null,
-      auth: authField(false),
-    },
+    communityForm: new CreateCommunity({
+      name: undefined,
+      title: undefined,
+      description: None,
+      nsfw: None,
+      icon: None,
+      banner: None,
+      posting_restricted_to_mods: None,
+      auth: undefined,
+    }),
     loading: false,
   };
 
@@ -70,30 +73,34 @@ export class CommunityForm extends Component<
     this.handleBannerUpload = this.handleBannerUpload.bind(this);
     this.handleBannerRemove = this.handleBannerRemove.bind(this);
 
-    let cv = this.props.community_view;
-    if (cv) {
-      this.state.communityForm = {
-        name: cv.community.name,
-        title: cv.community.title,
-        description: cv.community.description,
-        nsfw: cv.community.nsfw,
-        icon: cv.community.icon,
-        banner: cv.community.banner,
-        auth: authField(),
-      };
-    }
+    this.props.community_view.match({
+      some: cv => {
+        this.state.communityForm = new CreateCommunity({
+          name: cv.community.name,
+          title: cv.community.title,
+          description: cv.community.description,
+          nsfw: Some(cv.community.nsfw),
+          icon: cv.community.icon,
+          banner: cv.community.banner,
+          posting_restricted_to_mods: Some(
+            cv.community.posting_restricted_to_mods
+          ),
+          auth: undefined,
+        });
+      },
+      none: void 0,
+    });
 
     this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
   }
 
-  // TODO this should be checked out
   componentDidUpdate() {
     if (
       !this.state.loading &&
       (this.state.communityForm.name ||
         this.state.communityForm.title ||
-        this.state.communityForm.description)
+        this.state.communityForm.description.isSome())
     ) {
       window.onbeforeunload = () => true;
     } else {
@@ -114,23 +121,26 @@ export class CommunityForm extends Component<
             !this.state.loading &&
             (this.state.communityForm.name ||
               this.state.communityForm.title ||
-              this.state.communityForm.description)
+              this.state.communityForm.description.isSome())
           }
           message={i18n.t("block_leaving")}
         />
         <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
-          {!this.props.community_view && (
+          {this.props.community_view.isNone() && (
             <div class="form-group row">
-              <label class="col-12 col-form-label" htmlFor="community-name">
+              <label
+                class="col-12 col-sm-2 col-form-label"
+                htmlFor="community-name"
+              >
                 {i18n.t("name")}
                 <span
-                  class="pointer unselectable ml-2 text-muted"
+                  class="position-absolute pointer unselectable ml-2 text-muted"
                   data-tippy-content={i18n.t("name_explain")}
                 >
                   <Icon icon="help-circle" classes="icon-inline" />
                 </span>
               </label>
-              <div class="col-12">
+              <div class="col-12 col-sm-10">
                 <input
                   type="text"
                   id="community-name"
@@ -146,16 +156,19 @@ export class CommunityForm extends Component<
             </div>
           )}
           <div class="form-group row">
-            <label class="col-12 col-form-label" htmlFor="community-title">
+            <label
+              class="col-12 col-sm-2 col-form-label"
+              htmlFor="community-title"
+            >
               {i18n.t("display_name")}
               <span
-                class="pointer unselectable ml-2 text-muted"
+                class="position-absolute pointer unselectable ml-2 text-muted"
                 data-tippy-content={i18n.t("display_name_explain")}
               >
                 <Icon icon="help-circle" classes="icon-inline" />
               </span>
             </label>
-            <div class="col-12">
+            <div class="col-12 col-sm-10">
               <input
                 type="text"
                 id="community-title"
@@ -168,32 +181,39 @@ export class CommunityForm extends Component<
               />
             </div>
           </div>
-          <div class="form-group">
-            <label>{i18n.t("icon")}</label>
-            <ImageUploadForm
-              uploadTitle={i18n.t("upload_icon")}
-              imageSrc={this.state.communityForm.icon}
-              onUpload={this.handleIconUpload}
-              onRemove={this.handleIconRemove}
-              rounded
-            />
+          <div class="form-group row">
+            <label class="col-12 col-sm-2">{i18n.t("icon")}</label>
+            <div class="col-12 col-sm-10">
+              <ImageUploadForm
+                uploadTitle={i18n.t("upload_icon")}
+                imageSrc={this.state.communityForm.icon}
+                onUpload={this.handleIconUpload}
+                onRemove={this.handleIconRemove}
+                rounded
+              />
+            </div>
           </div>
-          <div class="form-group">
-            <label>{i18n.t("banner")}</label>
-            <ImageUploadForm
-              uploadTitle={i18n.t("upload_banner")}
-              imageSrc={this.state.communityForm.banner}
-              onUpload={this.handleBannerUpload}
-              onRemove={this.handleBannerRemove}
-            />
+          <div class="form-group row">
+            <label class="col-12 col-sm-2">{i18n.t("banner")}</label>
+            <div class="col-12 col-sm-10">
+              <ImageUploadForm
+                uploadTitle={i18n.t("upload_banner")}
+                imageSrc={this.state.communityForm.banner}
+                onUpload={this.handleBannerUpload}
+                onRemove={this.handleBannerRemove}
+              />
+            </div>
           </div>
           <div class="form-group row">
-            <label class="col-12 col-form-label" htmlFor={this.id}>
+            <label class="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
               {i18n.t("sidebar")}
             </label>
-            <div class="col-12">
+            <div class="col-12 col-sm-10">
               <MarkdownTextArea
                 initialContent={this.state.communityForm.description}
+                placeholder={Some("description")}
+                buttonTitle={None}
+                maxLength={None}
                 onContentChange={this.handleCommunityDescriptionChange}
               />
             </div>
@@ -201,22 +221,43 @@ export class CommunityForm extends Component<
 
           {this.props.enableNsfw && (
             <div class="form-group row">
-              <div class="col-12">
+              <legend class="col-form-label col-sm-2 pt-0">
+                {i18n.t("nsfw")}
+              </legend>
+              <div class="col-10">
                 <div class="form-check">
                   <input
-                    class="form-check-input"
+                    class="form-check-input position-static"
                     id="community-nsfw"
                     type="checkbox"
-                    checked={this.state.communityForm.nsfw}
+                    checked={toUndefined(this.state.communityForm.nsfw)}
                     onChange={linkEvent(this, this.handleCommunityNsfwChange)}
                   />
-                  <label class="form-check-label" htmlFor="community-nsfw">
-                    {i18n.t("nsfw")}
-                  </label>
                 </div>
               </div>
             </div>
           )}
+          <div class="form-group row">
+            <legend class="col-form-label col-6 pt-0">
+              {i18n.t("only_mods_can_post_in_community")}
+            </legend>
+            <div class="col-6">
+              <div class="form-check">
+                <input
+                  class="form-check-input position-static"
+                  id="community-only-mods-can-post"
+                  type="checkbox"
+                  checked={toUndefined(
+                    this.state.communityForm.posting_restricted_to_mods
+                  )}
+                  onChange={linkEvent(
+                    this,
+                    this.handleCommunityPostingRestrictedToMods
+                  )}
+                />
+              </div>
+            </div>
+          </div>
           <div class="form-group row">
             <div class="col-12">
               <button
@@ -226,13 +267,13 @@ export class CommunityForm extends Component<
               >
                 {this.state.loading ? (
                   <Spinner />
-                ) : this.props.community_view ? (
+                ) : this.props.community_view.isSome() ? (
                   capitalizeFirstLetter(i18n.t("save"))
                 ) : (
                   capitalizeFirstLetter(i18n.t("create"))
                 )}
               </button>
-              {this.props.community_view && (
+              {this.props.community_view.isSome() && (
                 <button
                   type="button"
                   class="btn btn-secondary"
@@ -251,17 +292,30 @@ export class CommunityForm extends Component<
   handleCreateCommunitySubmit(i: CommunityForm, event: any) {
     event.preventDefault();
     i.state.loading = true;
-    if (i.props.community_view) {
-      let form: EditCommunity = {
-        ...i.state.communityForm,
-        community_id: i.props.community_view.community.id,
-      };
-      WebSocketService.Instance.send(wsClient.editCommunity(form));
-    } else {
-      WebSocketService.Instance.send(
-        wsClient.createCommunity(i.state.communityForm)
-      );
-    }
+    let cForm = i.state.communityForm;
+    cForm.auth = auth().unwrap();
+
+    i.props.community_view.match({
+      some: cv => {
+        let form = new EditCommunity({
+          community_id: cv.community.id,
+          title: Some(cForm.title),
+          description: cForm.description,
+          icon: cForm.icon,
+          banner: cForm.banner,
+          nsfw: cForm.nsfw,
+          posting_restricted_to_mods: cForm.posting_restricted_to_mods,
+          auth: cForm.auth,
+        });
+
+        WebSocketService.Instance.send(wsClient.editCommunity(form));
+      },
+      none: () => {
+        WebSocketService.Instance.send(
+          wsClient.createCommunity(i.state.communityForm)
+        );
+      },
+    });
     i.setState(i.state);
   }
 
@@ -276,7 +330,7 @@ export class CommunityForm extends Component<
   }
 
   handleCommunityDescriptionChange(val: string) {
-    this.state.communityForm.description = val;
+    this.state.communityForm.description = Some(val);
     this.setState(this.state);
   }
 
@@ -285,27 +339,32 @@ export class CommunityForm extends Component<
     i.setState(i.state);
   }
 
+  handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
+    i.state.communityForm.posting_restricted_to_mods = event.target.checked;
+    i.setState(i.state);
+  }
+
   handleCancel(i: CommunityForm) {
     i.props.onCancel();
   }
 
   handleIconUpload(url: string) {
-    this.state.communityForm.icon = url;
+    this.state.communityForm.icon = Some(url);
     this.setState(this.state);
   }
 
   handleIconRemove() {
-    this.state.communityForm.icon = "";
+    this.state.communityForm.icon = Some("");
     this.setState(this.state);
   }
 
   handleBannerUpload(url: string) {
-    this.state.communityForm.banner = url;
+    this.state.communityForm.banner = Some(url);
     this.setState(this.state);
   }
 
   handleBannerRemove() {
-    this.state.communityForm.banner = "";
+    this.state.communityForm.banner = Some("");
     this.setState(this.state);
   }
 
@@ -313,47 +372,57 @@ export class CommunityForm extends Component<
     let op = wsUserOp(msg);
     console.log(msg);
     if (msg.error) {
-      toast(i18n.t(msg.error), "danger");
+      // Errors handled by top level pages
+      // toast(i18n.t(msg.error), "danger");
       this.state.loading = false;
       this.setState(this.state);
       return;
     } else if (op == UserOperation.CreateCommunity) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
+      let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
       this.state.loading = false;
       this.props.onCreate(data.community_view);
 
       // Update myUserInfo
       let community = data.community_view.community;
-      let person = UserService.Instance.myUserInfo.local_user_view.person;
-      UserService.Instance.myUserInfo.follows.push({
-        community,
-        follower: person,
-      });
-      UserService.Instance.myUserInfo.moderates.push({
-        community,
-        moderator: person,
+
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          let person = mui.local_user_view.person;
+          mui.follows.push({
+            community,
+            follower: person,
+          });
+          mui.moderates.push({
+            community,
+            moderator: person,
+          });
+        },
+        none: void 0,
       });
     } else if (op == UserOperation.EditCommunity) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
+      let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
       this.state.loading = false;
       this.props.onEdit(data.community_view);
       let community = data.community_view.community;
 
-      let followFound = UserService.Instance.myUserInfo.follows.findIndex(
-        f => f.community.id == community.id
-      );
-      if (followFound) {
-        UserService.Instance.myUserInfo.follows[followFound].community =
-          community;
-      }
-
-      let moderatesFound = UserService.Instance.myUserInfo.moderates.findIndex(
-        f => f.community.id == community.id
-      );
-      if (moderatesFound) {
-        UserService.Instance.myUserInfo.moderates[moderatesFound].community =
-          community;
-      }
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          let followFound = mui.follows.findIndex(
+            f => f.community.id == community.id
+          );
+          if (followFound) {
+            mui.follows[followFound].community = community;
+          }
+
+          let moderatesFound = mui.moderates.findIndex(
+            f => f.community.id == community.id
+          );
+          if (moderatesFound) {
+            mui.moderates[moderatesFound].community = community;
+          }
+        },
+        none: void 0,
+      });
     }
   }
 }
index 96db808fb189cb6adb90448e79bb580c1177ce1a..cc987053246c4a7ed2db183209ea80b5f5492ff3 100644 (file)
@@ -1,7 +1,7 @@
 import { Component } from "inferno";
 import { Link } from "inferno-router";
 import { CommunitySafe } from "lemmy-js-client";
-import { hostname, showAvatars } from "../../utils";
+import { hostname, relTags, showAvatars } from "../../utils";
 import { PictrsImage } from "../common/pictrs-image";
 
 interface CommunityLinkProps {
@@ -48,6 +48,7 @@ export class CommunityLink extends Component<CommunityLinkProps, any> {
         title={apubName}
         className={`${this.props.muted ? "text-muted" : ""}`}
         href={link}
+        rel={relTags}
       >
         {this.avatarAndName(displayName)}
       </a>
@@ -55,13 +56,15 @@ export class CommunityLink extends Component<CommunityLinkProps, any> {
   }
 
   avatarAndName(displayName: string) {
-    let community = this.props.community;
     return (
       <>
-        {!this.props.hideAvatar && community.icon && showAvatars() && (
-          <PictrsImage src={community.icon} icon />
-        )}
-        <span>{displayName}</span>
+        {!this.props.hideAvatar &&
+          showAvatars() &&
+          this.props.community.icon.match({
+            some: icon => <PictrsImage src={icon} icon />,
+            none: <></>,
+          })}
+        <span class="overflow-wrap-anywhere">{displayName}</span>
       </>
     );
   }
index 3ce5f848ee3855983ece3079c95a1d3f5b1289f8..4e8d949c4ca1b99f6119eff73d61dc1e97303445 100644 (file)
@@ -1,8 +1,11 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import {
   AddModToCommunityResponse,
   BanFromCommunityResponse,
+  BlockCommunityResponse,
   BlockPersonResponse,
+  CommentReportResponse,
   CommentResponse,
   CommentView,
   CommunityResponse,
@@ -14,40 +17,52 @@ import {
   GetPostsResponse,
   GetSiteResponse,
   ListingType,
+  PostReportResponse,
   PostResponse,
   PostView,
+  PurgeItemResponse,
   SortType,
+  toOption,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
-import { DataType, InitialFetchRequest } from "../../interfaces";
+import {
+  CommentViewType,
+  DataType,
+  InitialFetchRequest,
+} from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   commentsToFlatNodes,
   communityRSSUrl,
   createCommentLikeRes,
   createPostLikeFindRes,
   editCommentRes,
   editPostFindRes,
+  enableDownvotes,
+  enableNsfw,
   fetchLimit,
   getDataTypeFromProps,
   getPageFromProps,
   getSortTypeFromProps,
   notifyPost,
+  postToCommentSortType,
+  relTags,
   restoreScrollPosition,
   saveCommentRes,
   saveScrollPosition,
   setIsoData,
-  setOptionalAuth,
   setupTippy,
+  showLocal,
   toast,
+  updateCommunityBlock,
   updatePersonBlock,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { CommentNodes } from "../comment/comment-nodes";
 import { BannerIconHeader } from "../common/banner-icon-header";
@@ -57,11 +72,12 @@ import { Icon, Spinner } from "../common/icon";
 import { Paginator } from "../common/paginator";
 import { SortSelect } from "../common/sort-select";
 import { Sidebar } from "../community/sidebar";
+import { SiteSidebar } from "../home/site-sidebar";
 import { PostListings } from "../post/post-listings";
 import { CommunityLink } from "./community-link";
 
 interface State {
-  communityRes: GetCommunityResponse;
+  communityRes: Option<GetCommunityResponse>;
   siteRes: GetSiteResponse;
   communityName: string;
   communityLoading: boolean;
@@ -88,10 +104,15 @@ interface UrlParams {
 }
 
 export class Community extends Component<any, State> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(
+    this.context,
+    GetCommunityResponse,
+    GetPostsResponse,
+    GetCommentsResponse
+  );
   private subscription: Subscription;
   private emptyState: State = {
-    communityRes: undefined,
+    communityRes: None,
     communityName: this.props.match.params.name,
     communityLoading: true,
     postsLoading: true,
@@ -118,12 +139,21 @@ export class Community extends Component<any, State> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.communityRes = this.isoData.routeData[0];
-      if (this.state.dataType == DataType.Post) {
-        this.state.posts = this.isoData.routeData[1].posts;
-      } else {
-        this.state.comments = this.isoData.routeData[1].comments;
-      }
+      this.state.communityRes = Some(
+        this.isoData.routeData[0] as GetCommunityResponse
+      );
+      let postsRes = Some(this.isoData.routeData[1] as GetPostsResponse);
+      let commentsRes = Some(this.isoData.routeData[2] as GetCommentsResponse);
+
+      postsRes.match({
+        some: pvs => (this.state.posts = pvs.posts),
+        none: void 0,
+      });
+      commentsRes.match({
+        some: cvs => (this.state.comments = cvs.comments),
+        none: void 0,
+      });
+
       this.state.communityLoading = false;
       this.state.postsLoading = false;
       this.state.commentsLoading = false;
@@ -131,21 +161,24 @@ export class Community extends Component<any, State> {
       this.fetchCommunity();
       this.fetchData();
     }
-    setupTippy();
   }
 
   fetchCommunity() {
-    let form: GetCommunity = {
-      name: this.state.communityName ? this.state.communityName : null,
-      auth: authField(false),
-    };
+    let form = new GetCommunity({
+      name: Some(this.state.communityName),
+      id: None,
+      auth: auth(false).ok(),
+    });
     WebSocketService.Instance.send(wsClient.getCommunity(form));
   }
 
+  componentDidMount() {
+    setupTippy();
+  }
+
   componentWillUnmount() {
     saveScrollPosition(this.context);
     this.subscription.unsubscribe();
-    window.isoData.path = undefined;
   }
 
   static getDerivedStateFromProps(props: any): CommunityProps {
@@ -160,65 +193,66 @@ export class Community extends Component<any, State> {
     let pathSplit = req.path.split("/");
     let promises: Promise<any>[] = [];
 
-    // It can be /c/main, or /c/1
-    let idOrName = pathSplit[2];
-    let id: number;
-    let name_: string;
-    if (isNaN(Number(idOrName))) {
-      name_ = idOrName;
-    } else {
-      id = Number(idOrName);
-    }
-
-    let communityForm: GetCommunity = id ? { id } : { name: name_ };
-    setOptionalAuth(communityForm, req.auth);
+    let communityName = pathSplit[2];
+    let communityForm = new GetCommunity({
+      name: Some(communityName),
+      id: None,
+      auth: req.auth,
+    });
     promises.push(req.client.getCommunity(communityForm));
 
     let dataType: DataType = pathSplit[4]
       ? DataType[pathSplit[4]]
       : DataType.Post;
 
-    let sort: SortType = pathSplit[6]
-      ? SortType[pathSplit[6]]
-      : UserService.Instance.myUserInfo
-      ? Object.values(SortType)[
-          UserService.Instance.myUserInfo.local_user_view.local_user
-            .default_sort_type
-        ]
-      : SortType.Active;
+    let sort: Option<SortType> = toOption(
+      pathSplit[6]
+        ? SortType[pathSplit[6]]
+        : UserService.Instance.myUserInfo.match({
+            some: mui =>
+              Object.values(SortType)[
+                mui.local_user_view.local_user.default_sort_type
+              ],
+            none: SortType.Active,
+          })
+    );
 
-    let page = pathSplit[8] ? Number(pathSplit[8]) : 1;
+    let page = toOption(pathSplit[8] ? Number(pathSplit[8]) : 1);
 
     if (dataType == DataType.Post) {
-      let getPostsForm: GetPosts = {
+      let getPostsForm = new GetPosts({
+        community_name: Some(communityName),
+        community_id: None,
         page,
-        limit: fetchLimit,
+        limit: Some(fetchLimit),
         sort,
-        type_: ListingType.Community,
-        saved_only: false,
-      };
-      setOptionalAuth(getPostsForm, req.auth);
-      this.setName(getPostsForm, name_);
+        type_: Some(ListingType.All),
+        saved_only: Some(false),
+        auth: req.auth,
+      });
       promises.push(req.client.getPosts(getPostsForm));
+      promises.push(Promise.resolve());
     } else {
-      let getCommentsForm: GetComments = {
+      let getCommentsForm = new GetComments({
+        community_name: Some(communityName),
+        community_id: None,
         page,
-        limit: fetchLimit,
-        sort,
-        type_: ListingType.Community,
-        saved_only: false,
-      };
-      setOptionalAuth(getCommentsForm, req.auth);
+        limit: Some(fetchLimit),
+        max_depth: None,
+        sort: sort.map(postToCommentSortType),
+        type_: Some(ListingType.All),
+        saved_only: Some(false),
+        post_id: None,
+        parent_id: None,
+        auth: req.auth,
+      });
+      promises.push(Promise.resolve());
       promises.push(req.client.getComments(getCommentsForm));
     }
 
     return promises;
   }
 
-  static setName(obj: any, name_: string) {
-    obj.community_name = name_;
-  }
-
   componentDidUpdate(_: any, lastState: State) {
     if (
       lastState.dataType !== this.state.dataType ||
@@ -231,11 +265,18 @@ export class Community extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return `${this.state.communityRes.community_view.community.title} - ${this.state.siteRes.site_view.site.name}`;
+    return this.state.communityRes.match({
+      some: res =>
+        this.state.siteRes.site_view.match({
+          some: siteView =>
+            `${res.community_view.community.title} - ${siteView.site.name}`,
+          none: "",
+        }),
+      none: "",
+    });
   }
 
   render() {
-    let cv = this.state.communityRes?.community_view;
     return (
       <div class="container">
         {this.state.communityLoading ? (
@@ -243,67 +284,99 @@ export class Community extends Component<any, State> {
             <Spinner large />
           </h5>
         ) : (
-          <>
-            <HtmlTags
-              title={this.documentTitle}
-              path={this.context.router.route.match.url}
-              description={cv.community.description}
-              image={cv.community.icon}
-            />
+          this.state.communityRes.match({
+            some: res => (
+              <>
+                <HtmlTags
+                  title={this.documentTitle}
+                  path={this.context.router.route.match.url}
+                  description={res.community_view.community.description}
+                  image={res.community_view.community.icon}
+                />
 
-            <div class="row">
-              <div class="col-12 col-md-8">
-                {this.communityInfo()}
-                <div class="d-block d-md-none">
-                  <button
-                    class="btn btn-secondary d-inline-block mb-2 mr-3"
-                    onClick={linkEvent(this, this.handleShowSidebarMobile)}
-                  >
-                    {i18n.t("sidebar")}{" "}
-                    <Icon
-                      icon={
-                        this.state.showSidebarMobile
-                          ? `minus-square`
-                          : `plus-square`
-                      }
-                      classes="icon-inline"
+                <div class="row">
+                  <div class="col-12 col-md-8">
+                    {this.communityInfo()}
+                    <div class="d-block d-md-none">
+                      <button
+                        class="btn btn-secondary d-inline-block mb-2 mr-3"
+                        onClick={linkEvent(this, this.handleShowSidebarMobile)}
+                      >
+                        {i18n.t("sidebar")}{" "}
+                        <Icon
+                          icon={
+                            this.state.showSidebarMobile
+                              ? `minus-square`
+                              : `plus-square`
+                          }
+                          classes="icon-inline"
+                        />
+                      </button>
+                      {this.state.showSidebarMobile && (
+                        <>
+                          <Sidebar
+                            community_view={res.community_view}
+                            moderators={res.moderators}
+                            admins={this.state.siteRes.admins}
+                            online={res.online}
+                            enableNsfw={enableNsfw(this.state.siteRes)}
+                          />
+                          {!res.community_view.community.local &&
+                            res.site.match({
+                              some: site => (
+                                <SiteSidebar
+                                  site={site}
+                                  showLocal={showLocal(this.isoData)}
+                                  admins={None}
+                                  counts={None}
+                                  online={None}
+                                />
+                              ),
+                              none: <></>,
+                            })}
+                        </>
+                      )}
+                    </div>
+                    {this.selects()}
+                    {this.listings()}
+                    <Paginator
+                      page={this.state.page}
+                      onChange={this.handlePageChange}
                     />
-                  </button>
-                  {this.state.showSidebarMobile && (
+                  </div>
+                  <div class="d-none d-md-block col-md-4">
                     <Sidebar
-                      community_view={cv}
-                      moderators={this.state.communityRes.moderators}
+                      community_view={res.community_view}
+                      moderators={res.moderators}
                       admins={this.state.siteRes.admins}
-                      online={this.state.communityRes.online}
-                      enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
+                      online={res.online}
+                      enableNsfw={enableNsfw(this.state.siteRes)}
                     />
-                  )}
+                    {!res.community_view.community.local &&
+                      res.site.match({
+                        some: site => (
+                          <SiteSidebar
+                            site={site}
+                            showLocal={showLocal(this.isoData)}
+                            admins={None}
+                            counts={None}
+                            online={None}
+                          />
+                        ),
+                        none: <></>,
+                      })}
+                  </div>
                 </div>
-                {this.selects()}
-                {this.listings()}
-                <Paginator
-                  page={this.state.page}
-                  onChange={this.handlePageChange}
-                />
-              </div>
-              <div class="d-none d-md-block col-md-4">
-                <Sidebar
-                  community_view={cv}
-                  moderators={this.state.communityRes.moderators}
-                  admins={this.state.siteRes.admins}
-                  online={this.state.communityRes.online}
-                  enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
-                />
-              </div>
-            </div>
-          </>
+              </>
+            ),
+            none: <></>,
+          })
         )}
       </div>
     );
   }
 
   listings() {
-    let site = this.state.siteRes.site_view.site;
     return this.state.dataType == DataType.Post ? (
       this.state.postsLoading ? (
         <h5>
@@ -313,8 +386,8 @@ export class Community extends Component<any, State> {
         <PostListings
           posts={this.state.posts}
           removeDuplicates
-          enableDownvotes={site.enable_downvotes}
-          enableNsfw={site.enable_nsfw}
+          enableDownvotes={enableDownvotes(this.state.siteRes)}
+          enableNsfw={enableNsfw(this.state.siteRes)}
         />
       )
     ) : this.state.commentsLoading ? (
@@ -324,31 +397,42 @@ export class Community extends Component<any, State> {
     ) : (
       <CommentNodes
         nodes={commentsToFlatNodes(this.state.comments)}
+        viewType={CommentViewType.Flat}
         noIndent
         showContext
-        enableDownvotes={site.enable_downvotes}
+        enableDownvotes={enableDownvotes(this.state.siteRes)}
+        moderators={this.state.communityRes.map(r => r.moderators)}
+        admins={Some(this.state.siteRes.admins)}
+        maxCommentsShown={None}
       />
     );
   }
 
   communityInfo() {
-    let community = this.state.communityRes.community_view.community;
-    return (
-      <div class="mb-2">
-        <BannerIconHeader banner={community.banner} icon={community.icon} />
-        <h5 class="mb-0">{community.title}</h5>
-        <CommunityLink
-          community={community}
-          realLink
-          useApubName
-          muted
-          hideAvatar
-        />
-      </div>
-    );
+    return this.state.communityRes
+      .map(r => r.community_view.community)
+      .match({
+        some: community => (
+          <div class="mb-2">
+            <BannerIconHeader banner={community.banner} icon={community.icon} />
+            <h5 class="mb-0 overflow-wrap-anywhere">{community.title}</h5>
+            <CommunityLink
+              community={community}
+              realLink
+              useApubName
+              muted
+              hideAvatar
+            />
+          </div>
+        ),
+        none: <></>,
+      });
   }
 
   selects() {
+    let communityRss = this.state.communityRes.map(r =>
+      communityRSSUrl(r.community_view.community.actor_id, this.state.sort)
+    );
     return (
       <div class="mb-3">
         <span class="mr-3">
@@ -360,16 +444,17 @@ export class Community extends Component<any, State> {
         <span class="mr-2">
           <SortSelect sort={this.state.sort} onChange={this.handleSortChange} />
         </span>
-        <a
-          href={communityRSSUrl(
-            this.state.communityRes.community_view.community.actor_id,
-            this.state.sort
-          )}
-          title="RSS"
-          rel="noopener"
-        >
-          <Icon icon="rss" classes="text-muted small" />
-        </a>
+        {communityRss.match({
+          some: rss => (
+            <>
+              <a href={rss} title="RSS" rel={relTags}>
+                <Icon icon="rss" classes="text-muted small" />
+              </a>
+              <link rel="alternate" type="application/atom+xml" href={rss} />
+            </>
+          ),
+          none: <></>,
+        })}
       </div>
     );
   }
@@ -408,26 +493,31 @@ export class Community extends Component<any, State> {
 
   fetchData() {
     if (this.state.dataType == DataType.Post) {
-      let form: GetPosts = {
-        page: this.state.page,
-        limit: fetchLimit,
-        sort: this.state.sort,
-        type_: ListingType.Community,
-        community_name: this.state.communityName,
-        saved_only: false,
-        auth: authField(false),
-      };
+      let form = new GetPosts({
+        page: Some(this.state.page),
+        limit: Some(fetchLimit),
+        sort: Some(this.state.sort),
+        type_: Some(ListingType.All),
+        community_name: Some(this.state.communityName),
+        community_id: None,
+        saved_only: Some(false),
+        auth: auth(false).ok(),
+      });
       WebSocketService.Instance.send(wsClient.getPosts(form));
     } else {
-      let form: GetComments = {
-        page: this.state.page,
-        limit: fetchLimit,
-        sort: this.state.sort,
-        type_: ListingType.Community,
-        community_name: this.state.communityName,
-        saved_only: false,
-        auth: authField(false),
-      };
+      let form = new GetComments({
+        page: Some(this.state.page),
+        limit: Some(fetchLimit),
+        max_depth: None,
+        sort: Some(postToCommentSortType(this.state.sort)),
+        type_: Some(ListingType.All),
+        community_name: Some(this.state.communityName),
+        community_id: None,
+        saved_only: Some(false),
+        post_id: None,
+        parent_id: None,
+        auth: auth(false).ok(),
+      });
       WebSocketService.Instance.send(wsClient.getComments(form));
     }
   }
@@ -440,15 +530,20 @@ export class Community extends Component<any, State> {
       this.context.router.history.push("/");
       return;
     } else if (msg.reconnect) {
-      WebSocketService.Instance.send(
-        wsClient.communityJoin({
-          community_id: this.state.communityRes.community_view.community.id,
-        })
-      );
+      this.state.communityRes.match({
+        some: res => {
+          WebSocketService.Instance.send(
+            wsClient.communityJoin({
+              community_id: res.community_view.community.id,
+            })
+          );
+        },
+        none: void 0,
+      });
       this.fetchData();
     } else if (op == UserOperation.GetCommunity) {
-      let data = wsJsonToRes<GetCommunityResponse>(msg).data;
-      this.state.communityRes = data;
+      let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
+      this.state.communityRes = Some(data);
       this.state.communityLoading = false;
       this.setState(this.state);
       // TODO why is there no auth in this form?
@@ -462,18 +557,25 @@ export class Community extends Component<any, State> {
       op == UserOperation.DeleteCommunity ||
       op == UserOperation.RemoveCommunity
     ) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
-      this.state.communityRes.community_view = data.community_view;
+      let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
+      this.state.communityRes.match({
+        some: res => (res.community_view = data.community_view),
+        none: void 0,
+      });
       this.setState(this.state);
     } else if (op == UserOperation.FollowCommunity) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
-      this.state.communityRes.community_view.subscribed =
-        data.community_view.subscribed;
-      this.state.communityRes.community_view.counts.subscribers =
-        data.community_view.counts.subscribers;
+      let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
+      this.state.communityRes.match({
+        some: res => {
+          res.community_view.subscribed = data.community_view.subscribed;
+          res.community_view.counts.subscribers =
+            data.community_view.counts.subscribers;
+        },
+        none: void 0,
+      });
       this.setState(this.state);
     } else if (op == UserOperation.GetPosts) {
-      let data = wsJsonToRes<GetPostsResponse>(msg).data;
+      let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
       this.state.posts = data.posts;
       this.state.postsLoading = false;
       this.setState(this.state);
@@ -487,29 +589,39 @@ export class Community extends Component<any, State> {
       op == UserOperation.StickyPost ||
       op == UserOperation.SavePost
     ) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
       editPostFindRes(data.post_view, this.state.posts);
       this.setState(this.state);
     } else if (op == UserOperation.CreatePost) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
       this.state.posts.unshift(data.post_view);
       if (
-        UserService.Instance.myUserInfo?.local_user_view.local_user
-          .show_new_post_notifs
+        UserService.Instance.myUserInfo
+          .map(m => m.local_user_view.local_user.show_new_post_notifs)
+          .unwrapOr(false)
       ) {
         notifyPost(data.post_view, this.context.router);
       }
       this.setState(this.state);
     } else if (op == UserOperation.CreatePostLike) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
       createPostLikeFindRes(data.post_view, this.state.posts);
       this.setState(this.state);
     } else if (op == UserOperation.AddModToCommunity) {
-      let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
-      this.state.communityRes.moderators = data.moderators;
+      let data = wsJsonToRes<AddModToCommunityResponse>(
+        msg,
+        AddModToCommunityResponse
+      );
+      this.state.communityRes.match({
+        some: res => (res.moderators = data.moderators),
+        none: void 0,
+      });
       this.setState(this.state);
     } else if (op == UserOperation.BanFromCommunity) {
-      let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
+      let data = wsJsonToRes<BanFromCommunityResponse>(
+        msg,
+        BanFromCommunityResponse
+      );
 
       // TODO this might be incorrect
       this.state.posts
@@ -518,7 +630,7 @@ export class Community extends Component<any, State> {
 
       this.setState(this.state);
     } else if (op == UserOperation.GetComments) {
-      let data = wsJsonToRes<GetCommentsResponse>(msg).data;
+      let data = wsJsonToRes<GetCommentsResponse>(msg, GetCommentsResponse);
       this.state.comments = data.comments;
       this.state.commentsLoading = false;
       this.setState(this.state);
@@ -527,11 +639,11 @@ export class Community extends Component<any, State> {
       op == UserOperation.DeleteComment ||
       op == UserOperation.RemoveComment
     ) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       editCommentRes(data.comment_view, this.state.comments);
       this.setState(this.state);
     } else if (op == UserOperation.CreateComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
 
       // Necessary since it might be a user reply
       if (data.form_id) {
@@ -539,16 +651,43 @@ export class Community extends Component<any, State> {
         this.setState(this.state);
       }
     } else if (op == UserOperation.SaveComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       saveCommentRes(data.comment_view, this.state.comments);
       this.setState(this.state);
     } else if (op == UserOperation.CreateCommentLike) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       createCommentLikeRes(data.comment_view, this.state.comments);
       this.setState(this.state);
     } else if (op == UserOperation.BlockPerson) {
-      let data = wsJsonToRes<BlockPersonResponse>(msg).data;
+      let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
       updatePersonBlock(data);
+    } else if (op == UserOperation.CreatePostReport) {
+      let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (op == UserOperation.CreateCommentReport) {
+      let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (op == UserOperation.PurgeCommunity) {
+      let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+      if (data.success) {
+        toast(i18n.t("purge_success"));
+        this.context.router.history.push(`/`);
+      }
+    } else if (op == UserOperation.BlockCommunity) {
+      let data = wsJsonToRes<BlockCommunityResponse>(
+        msg,
+        BlockCommunityResponse
+      );
+      this.state.communityRes.match({
+        some: res => (res.community_view.blocked = data.blocked),
+        none: void 0,
+      });
+      updateCommunityBlock(data);
+      this.setState(this.state);
     }
   }
 }
index c43e727c7cbc7dd0b3b91100a6a4bb02760de5f6..9a36678433b964492b394e4ea34223f88a2aa15a 100644 (file)
@@ -1,15 +1,22 @@
+import { None } from "@sniptt/monads";
 import { Component } from "inferno";
-import { CommunityView, SiteView } from "lemmy-js-client";
+import { CommunityView, GetSiteResponse } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { UserService } from "../../services";
-import { isBrowser, setIsoData, toast, wsSubscribe } from "../../utils";
+import {
+  enableNsfw,
+  isBrowser,
+  setIsoData,
+  toast,
+  wsSubscribe,
+} from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
 import { CommunityForm } from "./community-form";
 
 interface CreateCommunityState {
-  site_view: SiteView;
+  siteRes: GetSiteResponse;
   loading: boolean;
 }
 
@@ -17,7 +24,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
   private isoData = setIsoData(this.context);
   private subscription: Subscription;
   private emptyState: CreateCommunityState = {
-    site_view: this.isoData.site_res.site_view,
+    siteRes: this.isoData.site_res,
     loading: false,
   };
   constructor(props: any, context: any) {
@@ -28,7 +35,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
     this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
 
-    if (!UserService.Instance.myUserInfo && isBrowser()) {
+    if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
       toast(i18n.t("not_logged_in"), "danger");
       this.context.router.history.push(`/login`);
     }
@@ -41,7 +48,10 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("create_community")} - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("create_community")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
@@ -50,6 +60,8 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         {this.state.loading ? (
           <h5>
@@ -60,8 +72,9 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
             <div class="col-12 col-lg-6 offset-lg-3 mb-4">
               <h5>{i18n.t("create_community")}</h5>
               <CommunityForm
+                community_view={None}
                 onCreate={this.handleCommunityCreate}
-                enableNsfw={this.state.site_view.site.enable_nsfw}
+                enableNsfw={enableNsfw(this.state.siteRes)}
               />
             </div>
           </div>
@@ -76,8 +89,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
 
   parseMessage(msg: any) {
     if (msg.error) {
-      // Toast errors are already handled by community-form
-      return;
+      toast(i18n.t(msg.error), "danger");
     }
   }
 }
index c0cb991901aaddf26bd36a4fbadc1647b31c7b6d..84879d7b25474e50a9e2d574624e45212f2f6f7f 100644 (file)
@@ -1,19 +1,33 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
   AddModToCommunity,
+  BlockCommunity,
   CommunityModeratorView,
   CommunityView,
   DeleteCommunity,
   FollowCommunity,
   PersonViewSafe,
+  PurgeCommunity,
   RemoveCommunity,
+  SubscribedType,
+  toUndefined,
 } from "lemmy-js-client";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
-import { authField, getUnixTime, mdToHtml, wsClient } from "../../utils";
+import {
+  amAdmin,
+  amMod,
+  amTopMod,
+  auth,
+  getUnixTime,
+  mdToHtml,
+  numToSI,
+  wsClient,
+} from "../../utils";
 import { BannerIconHeader } from "../common/banner-icon-header";
-import { Icon } from "../common/icon";
+import { Icon, PurgeWarning, Spinner } from "../common/icon";
 import { CommunityForm } from "../community/community-form";
 import { CommunityLink } from "../community/community-link";
 import { PersonListing } from "../person/person-listing";
@@ -23,15 +37,18 @@ interface SidebarProps {
   moderators: CommunityModeratorView[];
   admins: PersonViewSafe[];
   online: number;
-  enableNsfw: boolean;
+  enableNsfw?: boolean;
   showIcon?: boolean;
 }
 
 interface SidebarState {
+  removeReason: Option<string>;
+  removeExpires: Option<string>;
   showEdit: boolean;
   showRemoveDialog: boolean;
-  removeReason: string;
-  removeExpires: string;
+  showPurgeDialog: boolean;
+  purgeReason: Option<string>;
+  purgeLoading: boolean;
   showConfirmLeaveModTeam: boolean;
 }
 
@@ -39,8 +56,11 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
   private emptyState: SidebarState = {
     showEdit: false,
     showRemoveDialog: false,
-    removeReason: null,
-    removeExpires: null,
+    removeReason: None,
+    removeExpires: None,
+    showPurgeDialog: false,
+    purgeReason: None,
+    purgeLoading: false,
     showConfirmLeaveModTeam: false,
   };
 
@@ -58,7 +78,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
           this.sidebar()
         ) : (
           <CommunityForm
-            community_view={this.props.community_view}
+            community_view={Some(this.props.community_view)}
             onEdit={this.handleEditCommunity}
             onCancel={this.handleEditCancel}
             enableNsfw={this.props.enableNsfw}
@@ -76,7 +96,8 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
             {this.communityTitle()}
             {this.adminButtons()}
             {this.subscribe()}
-            {this.createPost()}
+            {this.canPost && this.createPost()}
+            {this.blockCommunity()}
           </div>
         </div>
         <div class="card border-secondary mb-3">
@@ -100,15 +121,22 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
             <BannerIconHeader icon={community.icon} banner={community.banner} />
           )}
           <span class="mr-2">{community.title}</span>
-          {subscribed && (
-            <a
+          {subscribed == SubscribedType.Subscribed && (
+            <button
               class="btn btn-secondary btn-sm mr-2"
-              href="#"
               onClick={linkEvent(this, this.handleUnsubscribe)}
             >
               <Icon icon="check" classes="icon-inline text-success mr-1" />
               {i18n.t("joined")}
-            </a>
+            </button>
+          )}
+          {subscribed == SubscribedType.Pending && (
+            <button
+              class="btn btn-warning mr-2"
+              onClick={linkEvent(this, this.handleUnsubscribe)}
+            >
+              {i18n.t("subscribe_pending")}
+            </button>
           )}
           {community.removed && (
             <small className="mr-2 text-muted font-italic">
@@ -143,72 +171,84 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
     return (
       <ul class="my-1 list-inline">
         <li className="list-inline-item badge badge-secondary">
-          {i18n.t("number_online", { count: this.props.online })}
+          {i18n.t("number_online", {
+            count: this.props.online,
+            formattedCount: numToSI(this.props.online),
+          })}
         </li>
         <li
           className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
+          data-tippy-content={i18n.t("active_users_in_the_last_day", {
             count: counts.users_active_day,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("day")}`}
+            formattedCount: counts.users_active_day,
+          })}
         >
           {i18n.t("number_of_users", {
             count: counts.users_active_day,
+            formattedCount: numToSI(counts.users_active_day),
           })}{" "}
           / {i18n.t("day")}
         </li>
         <li
           className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
+          data-tippy-content={i18n.t("active_users_in_the_last_week", {
             count: counts.users_active_week,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("week")}`}
+            formattedCount: counts.users_active_week,
+          })}
         >
           {i18n.t("number_of_users", {
             count: counts.users_active_week,
+            formattedCount: numToSI(counts.users_active_week),
           })}{" "}
           / {i18n.t("week")}
         </li>
         <li
           className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
+          data-tippy-content={i18n.t("active_users_in_the_last_month", {
             count: counts.users_active_month,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("month")}`}
+            formattedCount: counts.users_active_month,
+          })}
         >
           {i18n.t("number_of_users", {
             count: counts.users_active_month,
+            formattedCount: numToSI(counts.users_active_month),
           })}{" "}
           / {i18n.t("month")}
         </li>
         <li
           className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
+          data-tippy-content={i18n.t("active_users_in_the_last_six_months", {
             count: counts.users_active_half_year,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("number_of_months", {
-            count: 6,
-          })}`}
+            formattedCount: counts.users_active_half_year,
+          })}
         >
           {i18n.t("number_of_users", {
             count: counts.users_active_half_year,
+            formattedCount: numToSI(counts.users_active_half_year),
           })}{" "}
-          / {i18n.t("number_of_months", { count: 6 })}
+          / {i18n.t("number_of_months", { count: 6, formattedCount: 6 })}
         </li>
         <li className="list-inline-item badge badge-secondary">
           {i18n.t("number_of_subscribers", {
             count: counts.subscribers,
+            formattedCount: numToSI(counts.subscribers),
           })}
         </li>
         <li className="list-inline-item badge badge-secondary">
           {i18n.t("number_of_posts", {
             count: counts.posts,
+            formattedCount: numToSI(counts.posts),
           })}
         </li>
         <li className="list-inline-item badge badge-secondary">
           {i18n.t("number_of_comments", {
             count: counts.comments,
+            formattedCount: numToSI(counts.comments),
           })}
         </li>
         <li className="list-inline-item">
           <Link
-            className="badge badge-secondary"
+            className="badge badge-primary"
             to={`/modlog/community/${this.props.community_view.community.id}`}
           >
             {i18n.t("modlog")}
@@ -232,20 +272,16 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
   }
 
   createPost() {
-    let community_view = this.props.community_view;
+    let cv = this.props.community_view;
     return (
-      community_view.subscribed && (
-        <Link
-          className={`btn btn-secondary btn-block mb-2 ${
-            community_view.community.deleted || community_view.community.removed
-              ? "no-click"
-              : ""
-          }`}
-          to={`/create_post?community_id=${community_view.community.id}`}
-        >
-          {i18n.t("create_a_post")}
-        </Link>
-      )
+      <Link
+        className={`btn btn-secondary btn-block mb-2 ${
+          cv.community.deleted || cv.community.removed ? "no-click" : ""
+        }`}
+        to={`/create_post?community_id=${cv.community.id}`}
+      >
+        {i18n.t("create_a_post")}
+      </Link>
     );
   }
 
@@ -253,37 +289,60 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
     let community_view = this.props.community_view;
     return (
       <div class="mb-2">
-        {!community_view.subscribed && (
-          <a
+        {community_view.subscribed == SubscribedType.NotSubscribed && (
+          <button
             class="btn btn-secondary btn-block"
-            href="#"
             onClick={linkEvent(this, this.handleSubscribe)}
           >
             {i18n.t("subscribe")}
-          </a>
+          </button>
         )}
       </div>
     );
   }
 
-  description() {
-    let description = this.props.community_view.community.description;
+  blockCommunity() {
+    let community_view = this.props.community_view;
+    let blocked = this.props.community_view.blocked;
+
     return (
-      description && (
-        <div
-          className="md-div"
-          dangerouslySetInnerHTML={mdToHtml(description)}
-        />
-      )
+      <div class="mb-2">
+        {community_view.subscribed == SubscribedType.NotSubscribed &&
+          (blocked ? (
+            <button
+              class="btn btn-danger btn-block"
+              onClick={linkEvent(this, this.handleUnblock)}
+            >
+              {i18n.t("unblock_community")}
+            </button>
+          ) : (
+            <button
+              class="btn btn-danger btn-block"
+              onClick={linkEvent(this, this.handleBlock)}
+            >
+              {i18n.t("block_community")}
+            </button>
+          ))}
+      </div>
     );
   }
 
+  description() {
+    let description = this.props.community_view.community.description;
+    return description.match({
+      some: desc => (
+        <div className="md-div" dangerouslySetInnerHTML={mdToHtml(desc)} />
+      ),
+      none: <></>,
+    });
+  }
+
   adminButtons() {
     let community_view = this.props.community_view;
     return (
       <>
         <ul class="list-inline mb-1 text-muted font-weight-bold">
-          {this.canMod && (
+          {amMod(Some(this.props.moderators)) && (
             <>
               <li className="list-inline-item-action">
                 <button
@@ -295,7 +354,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
                   <Icon icon="edit" classes="icon-inline" />
                 </button>
               </li>
-              {!this.amTopMod &&
+              {!amTopMod(Some(this.props.moderators)) &&
                 (!this.state.showConfirmLeaveModTeam ? (
                   <li className="list-inline-item-action">
                     <button
@@ -334,7 +393,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
                     </li>
                   </>
                 ))}
-              {this.amTopMod && (
+              {amTopMod(Some(this.props.moderators)) && (
                 <li className="list-inline-item-action">
                   <button
                     class="btn btn-link text-muted d-inline-block"
@@ -361,7 +420,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
               )}
             </>
           )}
-          {this.canAdmin && (
+          {amAdmin(Some(this.props.admins)) && (
             <li className="list-inline-item">
               {!this.props.community_view.community.removed ? (
                 <button
@@ -378,12 +437,19 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
                   {i18n.t("restore")}
                 </button>
               )}
+              <button
+                class="btn btn-link text-muted d-inline-block"
+                onClick={linkEvent(this, this.handlePurgeCommunityShow)}
+                aria-label={i18n.t("purge_community")}
+              >
+                {i18n.t("purge_community")}
+              </button>
             </li>
           )}
         </ul>
         {this.state.showRemoveDialog && (
           <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
-            <div class="form-group row">
+            <div class="form-group">
               <label class="col-form-label" htmlFor="remove-reason">
                 {i18n.t("reason")}
               </label>
@@ -392,7 +458,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
                 id="remove-reason"
                 class="form-control mr-2"
                 placeholder={i18n.t("optional")}
-                value={this.state.removeReason}
+                value={toUndefined(this.state.removeReason)}
                 onInput={linkEvent(this, this.handleModRemoveReasonChange)}
               />
             </div>
@@ -401,13 +467,46 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
             {/*   <label class="col-form-label">Expires</label> */}
             {/*   <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
             {/* </div> */}
-            <div class="form-group row">
+            <div class="form-group">
               <button type="submit" class="btn btn-secondary">
                 {i18n.t("remove_community")}
               </button>
             </div>
           </form>
         )}
+        {this.state.showPurgeDialog && (
+          <form onSubmit={linkEvent(this, this.handlePurgeSubmit)}>
+            <div class="form-group">
+              <PurgeWarning />
+            </div>
+            <div class="form-group">
+              <label class="sr-only" htmlFor="purge-reason">
+                {i18n.t("reason")}
+              </label>
+              <input
+                type="text"
+                id="purge-reason"
+                class="form-control mr-2"
+                placeholder={i18n.t("reason")}
+                value={toUndefined(this.state.purgeReason)}
+                onInput={linkEvent(this, this.handlePurgeReasonChange)}
+              />
+            </div>
+            <div class="form-group">
+              {this.state.purgeLoading ? (
+                <Spinner />
+              ) : (
+                <button
+                  type="submit"
+                  class="btn btn-secondary"
+                  aria-label={i18n.t("purge_community")}
+                >
+                  {i18n.t("purge_community")}
+                </button>
+              )}
+            </div>
+          </form>
+        )}
       </>
     );
   }
@@ -429,11 +528,11 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
 
   handleDeleteClick(i: Sidebar, event: any) {
     event.preventDefault();
-    let deleteForm: DeleteCommunity = {
+    let deleteForm = new DeleteCommunity({
       community_id: i.props.community_view.community.id,
       deleted: !i.props.community_view.community.deleted,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.deleteCommunity(deleteForm));
   }
 
@@ -443,15 +542,20 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
   }
 
   handleLeaveModTeamClick(i: Sidebar) {
-    let form: AddModToCommunity = {
-      person_id: UserService.Instance.myUserInfo.local_user_view.person.id,
-      community_id: i.props.community_view.community.id,
-      added: false,
-      auth: authField(),
-    };
-    WebSocketService.Instance.send(wsClient.addModToCommunity(form));
-    i.state.showConfirmLeaveModTeam = false;
-    i.setState(i.state);
+    UserService.Instance.myUserInfo.match({
+      some: mui => {
+        let form = new AddModToCommunity({
+          person_id: mui.local_user_view.person.id,
+          community_id: i.props.community_view.community.id,
+          added: false,
+          auth: auth().unwrap(),
+        });
+        WebSocketService.Instance.send(wsClient.addModToCommunity(form));
+        i.state.showConfirmLeaveModTeam = false;
+        i.setState(i.state);
+      },
+      none: void 0,
+    });
   }
 
   handleCancelLeaveModTeamClick(i: Sidebar) {
@@ -462,59 +566,47 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
   handleUnsubscribe(i: Sidebar, event: any) {
     event.preventDefault();
     let community_id = i.props.community_view.community.id;
-    let form: FollowCommunity = {
+    let form = new FollowCommunity({
       community_id,
       follow: false,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.followCommunity(form));
 
     // Update myUserInfo
-    UserService.Instance.myUserInfo.follows =
-      UserService.Instance.myUserInfo.follows.filter(
-        i => i.community.id != community_id
-      );
+    UserService.Instance.myUserInfo.match({
+      some: mui =>
+        (mui.follows = mui.follows.filter(i => i.community.id != community_id)),
+      none: void 0,
+    });
   }
 
   handleSubscribe(i: Sidebar, event: any) {
     event.preventDefault();
     let community_id = i.props.community_view.community.id;
-    let form: FollowCommunity = {
+    let form = new FollowCommunity({
       community_id,
       follow: true,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.followCommunity(form));
 
     // Update myUserInfo
-    UserService.Instance.myUserInfo.follows.push({
-      community: i.props.community_view.community,
-      follower: UserService.Instance.myUserInfo.local_user_view.person,
+    UserService.Instance.myUserInfo.match({
+      some: mui =>
+        mui.follows.push({
+          community: i.props.community_view.community,
+          follower: mui.local_user_view.person,
+        }),
+      none: void 0,
     });
   }
 
-  private get amTopMod(): boolean {
+  get canPost(): boolean {
     return (
-      this.props.moderators[0].moderator.id ==
-      UserService.Instance.myUserInfo.local_user_view.person.id
-    );
-  }
-
-  get canMod(): boolean {
-    return (
-      UserService.Instance.myUserInfo &&
-      this.props.moderators
-        .map(m => m.moderator.id)
-        .includes(UserService.Instance.myUserInfo.local_user_view.person.id)
-    );
-  }
-
-  get canAdmin(): boolean {
-    return (
-      UserService.Instance.myUserInfo &&
-      this.props.admins
-        .map(a => a.person.id)
-        .includes(UserService.Instance.myUserInfo.local_user_view.person.id)
+      !this.props.community_view.community.posting_restricted_to_mods ||
+      amMod(Some(this.props.moderators)) ||
+      amAdmin(Some(this.props.admins))
     );
   }
 
@@ -524,28 +616,72 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
   }
 
   handleModRemoveReasonChange(i: Sidebar, event: any) {
-    i.state.removeReason = event.target.value;
+    i.state.removeReason = Some(event.target.value);
     i.setState(i.state);
   }
 
   handleModRemoveExpiresChange(i: Sidebar, event: any) {
-    console.log(event.target.value);
-    i.state.removeExpires = event.target.value;
+    i.state.removeExpires = Some(event.target.value);
     i.setState(i.state);
   }
 
   handleModRemoveSubmit(i: Sidebar, event: any) {
     event.preventDefault();
-    let removeForm: RemoveCommunity = {
+    let removeForm = new RemoveCommunity({
       community_id: i.props.community_view.community.id,
       removed: !i.props.community_view.community.removed,
       reason: i.state.removeReason,
-      expires: getUnixTime(i.state.removeExpires),
-      auth: authField(),
-    };
+      expires: i.state.removeExpires.map(getUnixTime),
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.removeCommunity(removeForm));
 
     i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
+
+  handlePurgeCommunityShow(i: Sidebar) {
+    i.state.showPurgeDialog = true;
+    i.state.showRemoveDialog = false;
+    i.setState(i.state);
+  }
+
+  handlePurgeReasonChange(i: Sidebar, event: any) {
+    i.state.purgeReason = Some(event.target.value);
+    i.setState(i.state);
+  }
+
+  handlePurgeSubmit(i: Sidebar, event: any) {
+    event.preventDefault();
+
+    let form = new PurgeCommunity({
+      community_id: i.props.community_view.community.id,
+      reason: i.state.purgeReason,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.purgeCommunity(form));
+
+    i.state.purgeLoading = true;
+    i.setState(i.state);
+  }
+
+  handleBlock(i: Sidebar, event: any) {
+    event.preventDefault();
+    let blockCommunityForm = new BlockCommunity({
+      community_id: i.props.community_view.community.id,
+      block: true,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
+  }
+
+  handleUnblock(i: Sidebar, event: any) {
+    event.preventDefault();
+    let blockCommunityForm = new BlockCommunity({
+      community_id: i.props.community_view.community.id,
+      block: false,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
+  }
 }
index cc8be245367a25e8682a9acc77ea3479c7712217..e01a09d7ac612a04ac274d987fd0b4d6b257f785 100644 (file)
@@ -1,28 +1,30 @@
+import { None, Some } from "@sniptt/monads";
 import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
 import {
-  GetSiteConfig,
-  GetSiteConfigResponse,
+  BannedPersonsResponse,
+  GetBannedPersons,
   GetSiteResponse,
-  SaveSiteConfig,
+  PersonViewSafe,
   SiteResponse,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { InitialFetchRequest } from "../../interfaces";
 import { WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
   isBrowser,
   randomStr,
   setIsoData,
+  showLocal,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
@@ -31,27 +33,20 @@ import { SiteForm } from "./site-form";
 
 interface AdminSettingsState {
   siteRes: GetSiteResponse;
-  siteConfigRes: GetSiteConfigResponse;
-  siteConfigForm: SaveSiteConfig;
+  banned: PersonViewSafe[];
   loading: boolean;
-  siteConfigLoading: boolean;
+  leaveAdminTeamLoading: boolean;
 }
 
 export class AdminSettings extends Component<any, AdminSettingsState> {
   private siteConfigTextAreaId = `site-config-${randomStr()}`;
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(this.context, BannedPersonsResponse);
   private subscription: Subscription;
   private emptyState: AdminSettingsState = {
     siteRes: this.isoData.site_res,
-    siteConfigForm: {
-      config_hjson: null,
-      auth: authField(),
-    },
-    siteConfigRes: {
-      config_hjson: null,
-    },
+    banned: [],
     loading: true,
-    siteConfigLoading: null,
+    leaveAdminTeamLoading: null,
   };
 
   constructor(props: any, context: any) {
@@ -64,23 +59,26 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.siteConfigRes = this.isoData.routeData[0];
-      this.state.siteConfigForm.config_hjson =
-        this.state.siteConfigRes.config_hjson;
-      this.state.siteConfigLoading = false;
+      this.state.banned = (
+        this.isoData.routeData[0] as BannedPersonsResponse
+      ).banned;
       this.state.loading = false;
     } else {
       WebSocketService.Instance.send(
-        wsClient.getSiteConfig({
-          auth: authField(),
+        wsClient.getBannedPersons({
+          auth: auth().unwrap(),
         })
       );
     }
   }
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
-    let form: GetSiteConfig = { auth: req.auth };
-    return [req.client.getSiteConfig(form)];
+    let promises: Promise<any>[] = [];
+
+    let bannedPersonsForm = new GetBannedPersons({ auth: req.auth.unwrap() });
+    promises.push(req.client.getBannedPersons(bannedPersonsForm));
+
+    return promises;
   }
 
   componentDidMount() {
@@ -97,18 +95,15 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("admin_settings")} - ${
-      this.state.siteRes.site_view.site.name
-    }`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("admin_settings")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
     return (
       <div class="container">
-        <HtmlTags
-          title={this.documentTitle}
-          path={this.context.router.route.match.url}
-        />
         {this.state.loading ? (
           <h5>
             <Spinner large />
@@ -116,13 +111,26 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
         ) : (
           <div class="row">
             <div class="col-12 col-md-6">
-              {this.state.siteRes.site_view.site.id && (
-                <SiteForm site={this.state.siteRes.site_view.site} />
-              )}
+              <HtmlTags
+                title={this.documentTitle}
+                path={this.context.router.route.match.url}
+                description={None}
+                image={None}
+              />
+              {this.state.siteRes.site_view.match({
+                some: siteView => (
+                  <SiteForm
+                    site={Some(siteView.site)}
+                    showLocal={showLocal(this.isoData)}
+                  />
+                ),
+                none: <></>,
+              })}
+            </div>
+            <div class="col-12 col-md-6">
               {this.admins()}
               {this.bannedUsers()}
             </div>
-            <div class="col-12 col-md-6">{this.adminSettings()}</div>
           </div>
         )}
       </div>
@@ -140,16 +148,32 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
             </li>
           ))}
         </ul>
+        {this.leaveAdmin()}
       </>
     );
   }
 
+  leaveAdmin() {
+    return (
+      <button
+        onClick={linkEvent(this, this.handleLeaveAdminTeam)}
+        class="btn btn-danger mb-2"
+      >
+        {this.state.leaveAdminTeamLoading ? (
+          <Spinner />
+        ) : (
+          i18n.t("leave_admin_team")
+        )}
+      </button>
+    );
+  }
+
   bannedUsers() {
     return (
       <>
         <h5>{i18n.t("banned_users")}</h5>
         <ul class="list-unstyled">
-          {this.state.siteRes.banned.map(banned => (
+          {this.state.banned.map(banned => (
             <li class="list-inline-item">
               <PersonListing person={banned.person} />
             </li>
@@ -159,58 +183,14 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     );
   }
 
-  adminSettings() {
-    return (
-      <div>
-        <h5>{i18n.t("admin_settings")}</h5>
-        <form onSubmit={linkEvent(this, this.handleSiteConfigSubmit)}>
-          <div class="form-group row">
-            <label
-              class="col-12 col-form-label"
-              htmlFor={this.siteConfigTextAreaId}
-            >
-              {i18n.t("site_config")}
-            </label>
-            <div class="col-12">
-              <textarea
-                id={this.siteConfigTextAreaId}
-                value={this.state.siteConfigForm.config_hjson}
-                onInput={linkEvent(this, this.handleSiteConfigHjsonChange)}
-                class="form-control text-monospace"
-                rows={3}
-              />
-            </div>
-          </div>
-          <div class="form-group row">
-            <div class="col-12">
-              <button type="submit" class="btn btn-secondary mr-2">
-                {this.state.siteConfigLoading ? (
-                  <Spinner />
-                ) : (
-                  capitalizeFirstLetter(i18n.t("save"))
-                )}
-              </button>
-            </div>
-          </div>
-        </form>
-      </div>
-    );
-  }
-
-  handleSiteConfigSubmit(i: AdminSettings, event: any) {
-    event.preventDefault();
-    i.state.siteConfigLoading = true;
+  handleLeaveAdminTeam(i: AdminSettings) {
+    i.state.leaveAdminTeamLoading = true;
     WebSocketService.Instance.send(
-      wsClient.saveSiteConfig(i.state.siteConfigForm)
+      wsClient.leaveAdmin({ auth: auth().unwrap() })
     );
     i.setState(i.state);
   }
 
-  handleSiteConfigHjsonChange(i: AdminSettings, event: any) {
-    i.state.siteConfigForm.config_hjson = event.target.value;
-    i.setState(i.state);
-  }
-
   parseMessage(msg: any) {
     let op = wsUserOp(msg);
     console.log(msg);
@@ -221,27 +201,23 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
       this.setState(this.state);
       return;
     } else if (op == UserOperation.EditSite) {
-      let data = wsJsonToRes<SiteResponse>(msg).data;
-      this.state.siteRes.site_view = data.site_view;
+      let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
+      this.state.siteRes.site_view = Some(data.site_view);
       this.setState(this.state);
       toast(i18n.t("site_saved"));
-    } else if (op == UserOperation.GetSiteConfig) {
-      let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
-      this.state.siteConfigRes = data;
+    } else if (op == UserOperation.GetBannedPersons) {
+      let data = wsJsonToRes<BannedPersonsResponse>(msg, BannedPersonsResponse);
+      this.state.banned = data.banned;
       this.state.loading = false;
-      this.state.siteConfigForm.config_hjson =
-        this.state.siteConfigRes.config_hjson;
       this.setState(this.state);
-      var textarea: any = document.getElementById(this.siteConfigTextAreaId);
-      autosize(textarea);
-    } else if (op == UserOperation.SaveSiteConfig) {
-      let data = wsJsonToRes<GetSiteConfigResponse>(msg).data;
-      this.state.siteConfigRes = data;
-      this.state.siteConfigForm.config_hjson =
-        this.state.siteConfigRes.config_hjson;
-      this.state.siteConfigLoading = false;
-      toast(i18n.t("site_saved"));
+    } else if (op == UserOperation.LeaveAdmin) {
+      let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+      this.state.siteRes.site_view = data.site_view;
       this.setState(this.state);
+      this.state.leaveAdminTeamLoading = false;
+      toast(i18n.t("left_admin_team"));
+      this.setState(this.state);
+      this.context.router.history.push("/");
     }
   }
 }
index 3cdb238d400191db11f92512f606df5caca38ae6..53559df9cbe5bc93defd43edc0f7d5a93cc888f2 100644 (file)
@@ -1,10 +1,12 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
-import { T } from "inferno-i18next";
+import { T } from "inferno-i18next-dess";
 import { Link } from "inferno-router";
 import {
   AddAdminResponse,
   BanPersonResponse,
   BlockPersonResponse,
+  CommentReportResponse,
   CommentResponse,
   CommentView,
   CommunityView,
@@ -16,46 +18,55 @@ import {
   ListCommunities,
   ListCommunitiesResponse,
   ListingType,
+  PostReportResponse,
   PostResponse,
   PostView,
+  PurgeItemResponse,
   SiteResponse,
   SortType,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
-import { DataType, InitialFetchRequest } from "../../interfaces";
+import {
+  CommentViewType,
+  DataType,
+  InitialFetchRequest,
+} from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   commentsToFlatNodes,
   createCommentLikeRes,
   createPostLikeFindRes,
   editCommentRes,
   editPostFindRes,
+  enableDownvotes,
+  enableNsfw,
   fetchLimit,
   getDataTypeFromProps,
   getListingTypeFromProps,
   getPageFromProps,
   getSortTypeFromProps,
-  mdToHtml,
+  isBrowser,
   notifyPost,
+  postToCommentSortType,
+  relTags,
   restoreScrollPosition,
   saveCommentRes,
   saveScrollPosition,
   setIsoData,
-  setOptionalAuth,
   setupTippy,
   showLocal,
   toast,
+  trendingFetchLimit,
   updatePersonBlock,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { CommentNodes } from "../comment/comment-nodes";
-import { BannerIconHeader } from "../common/banner-icon-header";
 import { DataTypeSelect } from "../common/data-type-select";
 import { HtmlTags } from "../common/html-tags";
 import { Icon, Spinner } from "../common/icon";
@@ -63,24 +74,23 @@ import { ListingTypeSelect } from "../common/listing-type-select";
 import { Paginator } from "../common/paginator";
 import { SortSelect } from "../common/sort-select";
 import { CommunityLink } from "../community/community-link";
-import { PersonListing } from "../person/person-listing";
 import { PostListings } from "../post/post-listings";
-import { SiteForm } from "./site-form";
+import { SiteSidebar } from "./site-sidebar";
 
 interface HomeState {
   trendingCommunities: CommunityView[];
   siteRes: GetSiteResponse;
-  showEditSite: boolean;
-  showSubscribedMobile: boolean;
-  showTrendingMobile: boolean;
-  showSidebarMobile: boolean;
-  loading: boolean;
   posts: PostView[];
   comments: CommentView[];
   listingType: ListingType;
   dataType: DataType;
   sort: SortType;
   page: number;
+  showSubscribedMobile: boolean;
+  showTrendingMobile: boolean;
+  showSidebarMobile: boolean;
+  subscribedCollapsed: boolean;
+  loading: boolean;
 }
 
 interface HomeProps {
@@ -98,19 +108,32 @@ interface UrlParams {
 }
 
 export class Home extends Component<any, HomeState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(
+    this.context,
+    GetPostsResponse,
+    GetCommentsResponse,
+    ListCommunitiesResponse
+  );
   private subscription: Subscription;
   private emptyState: HomeState = {
     trendingCommunities: [],
     siteRes: this.isoData.site_res,
-    showEditSite: false,
     showSubscribedMobile: false,
     showTrendingMobile: false,
     showSidebarMobile: false,
+    subscribedCollapsed: false,
     loading: true,
     posts: [],
     comments: [],
-    listingType: getListingTypeFromProps(this.props),
+    listingType: getListingTypeFromProps(
+      this.props,
+      ListingType[
+        this.isoData.site_res.site_view.match({
+          some: type_ => type_.site.default_post_listing_type,
+          none: ListingType.Local,
+        })
+      ]
+    ),
     dataType: getDataTypeFromProps(this.props),
     sort: getSortTypeFromProps(this.props),
     page: getPageFromProps(this.props),
@@ -120,7 +143,6 @@ export class Home extends Component<any, HomeState> {
     super(props, context);
 
     this.state = this.emptyState;
-    this.handleEditCancel = this.handleEditCancel.bind(this);
     this.handleSortChange = this.handleSortChange.bind(this);
     this.handleListingTypeChange = this.handleListingTypeChange.bind(this);
     this.handleDataTypeChange = this.handleDataTypeChange.bind(this);
@@ -131,28 +153,40 @@ export class Home extends Component<any, HomeState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      if (this.state.dataType == DataType.Post) {
-        this.state.posts = this.isoData.routeData[0].posts;
-      } else {
-        this.state.comments = this.isoData.routeData[0].comments;
+      let postsRes = Some(this.isoData.routeData[0] as GetPostsResponse);
+      let commentsRes = Some(this.isoData.routeData[1] as GetCommentsResponse);
+      let trendingRes = this.isoData.routeData[2] as ListCommunitiesResponse;
+
+      postsRes.match({
+        some: pvs => (this.state.posts = pvs.posts),
+        none: void 0,
+      });
+      commentsRes.match({
+        some: cvs => (this.state.comments = cvs.comments),
+        none: void 0,
+      });
+      this.state.trendingCommunities = trendingRes.communities;
+
+      if (isBrowser()) {
+        WebSocketService.Instance.send(
+          wsClient.communityJoin({ community_id: 0 })
+        );
       }
-      this.state.trendingCommunities = this.isoData.routeData[1].communities;
       this.state.loading = false;
     } else {
       this.fetchTrendingCommunities();
       this.fetchData();
     }
-
-    setupTippy();
   }
 
   fetchTrendingCommunities() {
-    let listCommunitiesForm: ListCommunities = {
-      type_: ListingType.Local,
-      sort: SortType.Hot,
-      limit: 6,
-      auth: authField(false),
-    };
+    let listCommunitiesForm = new ListCommunities({
+      type_: Some(ListingType.Local),
+      sort: Some(SortType.Hot),
+      limit: Some(trendingFetchLimit),
+      page: None,
+      auth: auth(false).ok(),
+    });
     WebSocketService.Instance.send(
       wsClient.listCommunities(listCommunitiesForm)
     );
@@ -160,22 +194,20 @@ export class Home extends Component<any, HomeState> {
 
   componentDidMount() {
     // This means it hasn't been set up yet
-    if (!this.state.siteRes.site_view) {
+    if (this.state.siteRes.site_view.isNone()) {
       this.context.router.history.push("/setup");
     }
-
-    WebSocketService.Instance.send(wsClient.communityJoin({ community_id: 0 }));
+    setupTippy();
   }
 
   componentWillUnmount() {
     saveScrollPosition(this.context);
     this.subscription.unsubscribe();
-    window.isoData.path = undefined;
   }
 
   static getDerivedStateFromProps(props: any): HomeProps {
     return {
-      listingType: getListingTypeFromProps(props),
+      listingType: getListingTypeFromProps(props, ListingType.Local),
       dataType: getDataTypeFromProps(props),
       sort: getSortTypeFromProps(props),
       page: getPageFromProps(props),
@@ -189,54 +221,72 @@ export class Home extends Component<any, HomeState> {
       : DataType.Post;
 
     // TODO figure out auth default_listingType, default_sort_type
-    let type_: ListingType = pathSplit[5]
-      ? ListingType[pathSplit[5]]
-      : UserService.Instance.myUserInfo
-      ? Object.values(ListingType)[
-          UserService.Instance.myUserInfo.local_user_view.local_user
-            .default_listing_type
-        ]
-      : ListingType.Local;
-    let sort: SortType = pathSplit[7]
-      ? SortType[pathSplit[7]]
-      : UserService.Instance.myUserInfo
-      ? Object.values(SortType)[
-          UserService.Instance.myUserInfo.local_user_view.local_user
-            .default_sort_type
-        ]
-      : SortType.Active;
-
-    let page = pathSplit[9] ? Number(pathSplit[9]) : 1;
+    let type_: Option<ListingType> = Some(
+      pathSplit[5]
+        ? ListingType[pathSplit[5]]
+        : UserService.Instance.myUserInfo.match({
+            some: mui =>
+              Object.values(ListingType)[
+                mui.local_user_view.local_user.default_listing_type
+              ],
+            none: ListingType.Local,
+          })
+    );
+    let sort: Option<SortType> = Some(
+      pathSplit[7]
+        ? SortType[pathSplit[7]]
+        : UserService.Instance.myUserInfo.match({
+            some: mui =>
+              Object.values(SortType)[
+                mui.local_user_view.local_user.default_sort_type
+              ],
+            none: SortType.Active,
+          })
+    );
+
+    let page = Some(pathSplit[9] ? Number(pathSplit[9]) : 1);
 
     let promises: Promise<any>[] = [];
 
     if (dataType == DataType.Post) {
-      let getPostsForm: GetPosts = {
+      let getPostsForm = new GetPosts({
+        community_id: None,
+        community_name: None,
+        type_,
         page,
-        limit: fetchLimit,
+        limit: Some(fetchLimit),
         sort,
-        type_,
-        saved_only: false,
-      };
-      setOptionalAuth(getPostsForm, req.auth);
+        saved_only: Some(false),
+        auth: req.auth,
+      });
+
       promises.push(req.client.getPosts(getPostsForm));
+      promises.push(Promise.resolve());
     } else {
-      let getCommentsForm: GetComments = {
+      let getCommentsForm = new GetComments({
+        community_id: None,
+        community_name: None,
         page,
-        limit: fetchLimit,
-        sort,
+        limit: Some(fetchLimit),
+        max_depth: None,
+        sort: sort.map(postToCommentSortType),
         type_,
-        saved_only: false,
-      };
-      setOptionalAuth(getCommentsForm, req.auth);
+        saved_only: Some(false),
+        post_id: None,
+        parent_id: None,
+        auth: req.auth,
+      });
+      promises.push(Promise.resolve());
       promises.push(req.client.getComments(getCommentsForm));
     }
 
-    let trendingCommunitiesForm: ListCommunities = {
-      type_: ListingType.Local,
-      sort: SortType.Hot,
-      limit: 6,
-    };
+    let trendingCommunitiesForm = new ListCommunities({
+      type_: Some(ListingType.Local),
+      sort: Some(SortType.Hot),
+      limit: Some(trendingFetchLimit),
+      page: None,
+      auth: req.auth,
+    });
     promises.push(req.client.listCommunities(trendingCommunitiesForm));
 
     return promises;
@@ -255,13 +305,14 @@ export class Home extends Component<any, HomeState> {
   }
 
   get documentTitle(): string {
-    return `${
-      this.state.siteRes.site_view
-        ? this.state.siteRes.site_view.site.description
-          ? `${this.state.siteRes.site_view.site.name} - ${this.state.siteRes.site_view.site.description}`
-          : this.state.siteRes.site_view.site.name
-        : "Lemmy"
-    }`;
+    return this.state.siteRes.site_view.match({
+      some: siteView =>
+        siteView.site.description.match({
+          some: desc => `${siteView.site.name} - ${desc}`,
+          none: siteView.site.name,
+        }),
+      none: "Lemmy",
+    });
   }
 
   render() {
@@ -270,8 +321,10 @@ export class Home extends Component<any, HomeState> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
-        {this.state.siteRes.site_view?.site && (
+        {this.state.siteRes.site_view.isSome() && (
           <div class="row">
             <main role="main" class="col-12 col-md-8">
               <div class="d-block d-md-none">{this.mobileView()}</div>
@@ -284,27 +337,34 @@ export class Home extends Component<any, HomeState> {
     );
   }
 
+  get hasFollows(): boolean {
+    return UserService.Instance.myUserInfo.match({
+      some: mui => mui.follows.length > 0,
+      none: false,
+    });
+  }
+
   mobileView() {
+    let siteRes = this.state.siteRes;
     return (
       <div class="row">
         <div class="col-12">
-          {UserService.Instance.myUserInfo &&
-            UserService.Instance.myUserInfo.follows.length > 0 && (
-              <button
-                class="btn btn-secondary d-inline-block mb-2 mr-3"
-                onClick={linkEvent(this, this.handleShowSubscribedMobile)}
-              >
-                {i18n.t("subscribed")}{" "}
-                <Icon
-                  icon={
-                    this.state.showSubscribedMobile
-                      ? `minus-square`
-                      : `plus-square`
-                  }
-                  classes="icon-inline"
-                />
-              </button>
-            )}
+          {this.hasFollows && (
+            <button
+              class="btn btn-secondary d-inline-block mb-2 mr-3"
+              onClick={linkEvent(this, this.handleShowSubscribedMobile)}
+            >
+              {i18n.t("subscribed")}{" "}
+              <Icon
+                icon={
+                  this.state.showSubscribedMobile
+                    ? `minus-square`
+                    : `plus-square`
+                }
+                classes="icon-inline"
+              />
+            </button>
+          )}
           <button
             class="btn btn-secondary d-inline-block mb-2 mr-3"
             onClick={linkEvent(this, this.handleShowTrendingMobile)}
@@ -329,19 +389,27 @@ export class Home extends Component<any, HomeState> {
               classes="icon-inline"
             />
           </button>
-          {this.state.showSubscribedMobile && (
-            <div class="col-12 card border-secondary mb-3">
-              <div class="card-body">{this.subscribedCommunities()}</div>
-            </div>
-          )}
+          {this.state.showSidebarMobile &&
+            siteRes.site_view.match({
+              some: siteView => (
+                <SiteSidebar
+                  site={siteView.site}
+                  admins={Some(siteRes.admins)}
+                  counts={Some(siteView.counts)}
+                  online={Some(siteRes.online)}
+                  showLocal={showLocal(this.isoData)}
+                />
+              ),
+              none: <></>,
+            })}
           {this.state.showTrendingMobile && (
             <div class="col-12 card border-secondary mb-3">
               <div class="card-body">{this.trendingCommunities()}</div>
             </div>
           )}
-          {this.state.showSidebarMobile && (
+          {this.state.showSubscribedMobile && (
             <div class="col-12 card border-secondary mb-3">
-              <div class="card-body">{this.sidebar()}</div>
+              <div class="card-body">{this.subscribedCommunities()}</div>
             </div>
           )}
         </div>
@@ -350,6 +418,7 @@ export class Home extends Component<any, HomeState> {
   }
 
   mySidebar() {
+    let siteRes = this.state.siteRes;
     return (
       <div>
         {!this.state.loading && (
@@ -361,17 +430,23 @@ export class Home extends Component<any, HomeState> {
                 {this.exploreCommunitiesButton()}
               </div>
             </div>
-
-            {UserService.Instance.myUserInfo &&
-              UserService.Instance.myUserInfo.follows.length > 0 && (
-                <div class="card border-secondary mb-3">
-                  <div class="card-body">{this.subscribedCommunities()}</div>
-                </div>
-              )}
-
-            <div class="card border-secondary mb-3">
-              <div class="card-body">{this.sidebar()}</div>
-            </div>
+            {siteRes.site_view.match({
+              some: siteView => (
+                <SiteSidebar
+                  site={siteView.site}
+                  admins={Some(siteRes.admins)}
+                  counts={Some(siteView.counts)}
+                  online={Some(siteRes.online)}
+                  showLocal={showLocal(this.isoData)}
+                />
+              ),
+              none: <></>,
+            })}
+            {this.hasFollows && (
+              <div class="card border-secondary mb-3">
+                <div class="card-body">{this.subscribedCommunities()}</div>
+              </div>
+            )}
           </div>
         )}
       </div>
@@ -420,39 +495,36 @@ export class Home extends Component<any, HomeState> {
     return (
       <div>
         <h5>
-          <T i18nKey="subscribed_to_communities">
+          <T class="d-inline" i18nKey="subscribed_to_communities">
             #
             <Link className="text-body" to="/communities">
               #
             </Link>
           </T>
+          <button
+            class="btn btn-sm text-muted"
+            onClick={linkEvent(this, this.handleCollapseSubscribe)}
+            aria-label={i18n.t("collapse")}
+            data-tippy-content={i18n.t("collapse")}
+          >
+            {this.state.subscribedCollapsed ? (
+              <Icon icon="plus-square" classes="icon-inline" />
+            ) : (
+              <Icon icon="minus-square" classes="icon-inline" />
+            )}
+          </button>
         </h5>
-        <ul class="list-inline mb-0">
-          {UserService.Instance.myUserInfo.follows.map(cfv => (
-            <li class="list-inline-item d-inline-block">
-              <CommunityLink community={cfv.community} />
-            </li>
-          ))}
-        </ul>
-      </div>
-    );
-  }
-
-  sidebar() {
-    let site = this.state.siteRes.site_view.site;
-    return (
-      <div>
-        {!this.state.showEditSite ? (
-          <div>
-            <div class="mb-2">
-              {this.siteName()}
-              {this.adminButtons()}
-            </div>
-            <BannerIconHeader banner={site.banner} />
-            {this.siteInfo()}
-          </div>
-        ) : (
-          <SiteForm site={site} onCancel={this.handleEditCancel} />
+        {!this.state.subscribedCollapsed && (
+          <ul class="list-inline mb-0">
+            {UserService.Instance.myUserInfo
+              .map(m => m.follows)
+              .unwrapOr([])
+              .map(cfv => (
+                <li class="list-inline-item d-inline-block">
+                  <CommunityLink community={cfv.community} />
+                </li>
+              ))}
+          </ul>
         )}
       </div>
     );
@@ -468,148 +540,6 @@ export class Home extends Component<any, HomeState> {
     );
   }
 
-  siteInfo() {
-    let site = this.state.siteRes.site_view.site;
-    return (
-      <div>
-        {site.description && <h6>{site.description}</h6>}
-        {site.sidebar && this.siteSidebar()}
-        {this.badges()}
-        {this.admins()}
-      </div>
-    );
-  }
-
-  siteName() {
-    let site = this.state.siteRes.site_view.site;
-    return site.name && <h5 class="mb-0">{site.name}</h5>;
-  }
-
-  admins() {
-    return (
-      <ul class="mt-1 list-inline small mb-0">
-        <li class="list-inline-item">{i18n.t("admins")}:</li>
-        {this.state.siteRes.admins.map(av => (
-          <li class="list-inline-item">
-            <PersonListing person={av.person} />
-          </li>
-        ))}
-      </ul>
-    );
-  }
-
-  badges() {
-    let counts = this.state.siteRes.site_view.counts;
-    return (
-      <ul class="my-2 list-inline">
-        <li className="list-inline-item badge badge-secondary">
-          {i18n.t("number_online", { count: this.state.siteRes.online })}
-        </li>
-        <li
-          className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
-            count: counts.users_active_day,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("day")}`}
-        >
-          {i18n.t("number_of_users", {
-            count: counts.users_active_day,
-          })}{" "}
-          / {i18n.t("day")}
-        </li>
-        <li
-          className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
-            count: counts.users_active_week,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("week")}`}
-        >
-          {i18n.t("number_of_users", {
-            count: counts.users_active_week,
-          })}{" "}
-          / {i18n.t("week")}
-        </li>
-        <li
-          className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
-            count: counts.users_active_month,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("month")}`}
-        >
-          {i18n.t("number_of_users", {
-            count: counts.users_active_month,
-          })}{" "}
-          / {i18n.t("month")}
-        </li>
-        <li
-          className="list-inline-item badge badge-secondary pointer"
-          data-tippy-content={`${i18n.t("number_of_users", {
-            count: counts.users_active_half_year,
-          })} ${i18n.t("active_in_the_last")} ${i18n.t("number_of_months", {
-            count: 6,
-          })}`}
-        >
-          {i18n.t("number_of_users", {
-            count: counts.users_active_half_year,
-          })}{" "}
-          / {i18n.t("number_of_months", { count: 6 })}
-        </li>
-        <li className="list-inline-item badge badge-secondary">
-          {i18n.t("number_of_users", {
-            count: counts.users,
-          })}
-        </li>
-        <li className="list-inline-item badge badge-secondary">
-          {i18n.t("number_of_communities", {
-            count: counts.communities,
-          })}
-        </li>
-        <li className="list-inline-item badge badge-secondary">
-          {i18n.t("number_of_posts", {
-            count: counts.posts,
-          })}
-        </li>
-        <li className="list-inline-item badge badge-secondary">
-          {i18n.t("number_of_comments", {
-            count: counts.comments,
-          })}
-        </li>
-        <li className="list-inline-item">
-          <Link className="badge badge-secondary" to="/modlog">
-            {i18n.t("modlog")}
-          </Link>
-        </li>
-      </ul>
-    );
-  }
-
-  adminButtons() {
-    return (
-      this.canAdmin && (
-        <ul class="list-inline mb-1 text-muted font-weight-bold">
-          <li className="list-inline-item-action">
-            <button
-              class="btn btn-link d-inline-block text-muted"
-              onClick={linkEvent(this, this.handleEditClick)}
-              aria-label={i18n.t("edit")}
-              data-tippy-content={i18n.t("edit")}
-            >
-              <Icon icon="edit" classes="icon-inline" />
-            </button>
-          </li>
-        </ul>
-      )
-    );
-  }
-
-  siteSidebar() {
-    return (
-      <div
-        className="md-div"
-        dangerouslySetInnerHTML={mdToHtml(
-          this.state.siteRes.site_view.site.sidebar
-        )}
-      />
-    );
-  }
-
   posts() {
     return (
       <div class="main-content-wrapper">
@@ -632,27 +562,36 @@ export class Home extends Component<any, HomeState> {
   }
 
   listings() {
-    let site = this.state.siteRes.site_view.site;
     return this.state.dataType == DataType.Post ? (
       <PostListings
         posts={this.state.posts}
         showCommunity
         removeDuplicates
-        enableDownvotes={site.enable_downvotes}
-        enableNsfw={site.enable_nsfw}
+        enableDownvotes={enableDownvotes(this.state.siteRes)}
+        enableNsfw={enableNsfw(this.state.siteRes)}
       />
     ) : (
       <CommentNodes
         nodes={commentsToFlatNodes(this.state.comments)}
+        viewType={CommentViewType.Flat}
+        moderators={None}
+        admins={None}
+        maxCommentsShown={None}
         noIndent
         showCommunity
         showContext
-        enableDownvotes={site.enable_downvotes}
+        enableDownvotes={enableDownvotes(this.state.siteRes)}
       />
     );
   }
 
   selects() {
+    let allRss = `/feeds/all.xml?sort=${this.state.sort}`;
+    let localRss = `/feeds/local.xml?sort=${this.state.sort}`;
+    let frontRss = auth(false)
+      .ok()
+      .map(auth => `/feeds/front/${auth}.xml?sort=${this.state.sort}`);
+
     return (
       <div className="mb-3">
         <span class="mr-3">
@@ -665,6 +604,7 @@ export class Home extends Component<any, HomeState> {
           <ListingTypeSelect
             type_={this.state.listingType}
             showLocal={showLocal(this.isoData)}
+            showSubscribed
             onChange={this.handleListingTypeChange}
           />
         </span>
@@ -672,56 +612,37 @@ export class Home extends Component<any, HomeState> {
           <SortSelect sort={this.state.sort} onChange={this.handleSortChange} />
         </span>
         {this.state.listingType == ListingType.All && (
-          <a
-            href={`/feeds/all.xml?sort=${this.state.sort}`}
-            rel="noopener"
-            title="RSS"
-          >
-            <Icon icon="rss" classes="text-muted small" />
-          </a>
+          <>
+            <a href={allRss} rel={relTags} title="RSS">
+              <Icon icon="rss" classes="text-muted small" />
+            </a>
+            <link rel="alternate" type="application/atom+xml" href={allRss} />
+          </>
         )}
         {this.state.listingType == ListingType.Local && (
-          <a
-            href={`/feeds/local.xml?sort=${this.state.sort}`}
-            rel="noopener"
-            title="RSS"
-          >
-            <Icon icon="rss" classes="text-muted small" />
-          </a>
-        )}
-        {UserService.Instance.myUserInfo &&
-          this.state.listingType == ListingType.Subscribed && (
-            <a
-              href={`/feeds/front/${UserService.Instance.auth}.xml?sort=${this.state.sort}`}
-              title="RSS"
-              rel="noopener"
-            >
+          <>
+            <a href={localRss} rel={relTags} title="RSS">
               <Icon icon="rss" classes="text-muted small" />
             </a>
-          )}
+            <link rel="alternate" type="application/atom+xml" href={localRss} />
+          </>
+        )}
+        {this.state.listingType == ListingType.Subscribed &&
+          frontRss.match({
+            some: rss => (
+              <>
+                <a href={rss} title="RSS" rel={relTags}>
+                  <Icon icon="rss" classes="text-muted small" />
+                </a>
+                <link rel="alternate" type="application/atom+xml" href={rss} />
+              </>
+            ),
+            none: <></>,
+          })}
       </div>
     );
   }
 
-  get canAdmin(): boolean {
-    return (
-      UserService.Instance.myUserInfo &&
-      this.state.siteRes.admins
-        .map(a => a.person.id)
-        .includes(UserService.Instance.myUserInfo.local_user_view.person.id)
-    );
-  }
-
-  handleEditClick(i: Home) {
-    i.state.showEditSite = true;
-    i.setState(i.state);
-  }
-
-  handleEditCancel() {
-    this.state.showEditSite = false;
-    this.setState(this.state);
-  }
-
   handleShowSubscribedMobile(i: Home) {
     i.state.showSubscribedMobile = !i.state.showSubscribedMobile;
     i.setState(i.state);
@@ -737,6 +658,11 @@ export class Home extends Component<any, HomeState> {
     i.setState(i.state);
   }
 
+  handleCollapseSubscribe(i: Home) {
+    i.state.subscribedCollapsed = !i.state.subscribedCollapsed;
+    i.setState(i.state);
+  }
+
   handlePageChange(page: number) {
     this.updateUrl({ page });
     window.scrollTo(0, 0);
@@ -759,24 +685,32 @@ export class Home extends Component<any, HomeState> {
 
   fetchData() {
     if (this.state.dataType == DataType.Post) {
-      let getPostsForm: GetPosts = {
-        page: this.state.page,
-        limit: fetchLimit,
-        sort: this.state.sort,
-        type_: this.state.listingType,
-        saved_only: false,
-        auth: authField(false),
-      };
+      let getPostsForm = new GetPosts({
+        community_id: None,
+        community_name: None,
+        page: Some(this.state.page),
+        limit: Some(fetchLimit),
+        sort: Some(this.state.sort),
+        saved_only: Some(false),
+        auth: auth(false).ok(),
+        type_: Some(this.state.listingType),
+      });
+
       WebSocketService.Instance.send(wsClient.getPosts(getPostsForm));
     } else {
-      let getCommentsForm: GetComments = {
-        page: this.state.page,
-        limit: fetchLimit,
-        sort: this.state.sort,
-        type_: this.state.listingType,
-        saved_only: false,
-        auth: authField(false),
-      };
+      let getCommentsForm = new GetComments({
+        community_id: None,
+        community_name: None,
+        page: Some(this.state.page),
+        limit: Some(fetchLimit),
+        max_depth: None,
+        sort: Some(postToCommentSortType(this.state.sort)),
+        saved_only: Some(false),
+        post_id: None,
+        parent_id: None,
+        auth: auth(false).ok(),
+        type_: Some(this.state.listingType),
+      });
       WebSocketService.Instance.send(wsClient.getComments(getCommentsForm));
     }
   }
@@ -793,47 +727,55 @@ export class Home extends Component<any, HomeState> {
       );
       this.fetchData();
     } else if (op == UserOperation.ListCommunities) {
-      let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
+      let data = wsJsonToRes<ListCommunitiesResponse>(
+        msg,
+        ListCommunitiesResponse
+      );
       this.state.trendingCommunities = data.communities;
       this.setState(this.state);
     } else if (op == UserOperation.EditSite) {
-      let data = wsJsonToRes<SiteResponse>(msg).data;
-      this.state.siteRes.site_view = data.site_view;
-      this.state.showEditSite = false;
+      let data = wsJsonToRes<SiteResponse>(msg, SiteResponse);
+      this.state.siteRes.site_view = Some(data.site_view);
       this.setState(this.state);
       toast(i18n.t("site_saved"));
     } else if (op == UserOperation.GetPosts) {
-      let data = wsJsonToRes<GetPostsResponse>(msg).data;
+      let data = wsJsonToRes<GetPostsResponse>(msg, GetPostsResponse);
       this.state.posts = data.posts;
       this.state.loading = false;
       this.setState(this.state);
+      WebSocketService.Instance.send(
+        wsClient.communityJoin({ community_id: 0 })
+      );
       restoreScrollPosition(this.context);
       setupTippy();
     } else if (op == UserOperation.CreatePost) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
       // NSFW check
       let nsfw = data.post_view.post.nsfw || data.post_view.community.nsfw;
       let nsfwCheck =
         !nsfw ||
         (nsfw &&
-          UserService.Instance.myUserInfo &&
-          UserService.Instance.myUserInfo.local_user_view.local_user.show_nsfw);
+          UserService.Instance.myUserInfo
+            .map(m => m.local_user_view.local_user.show_nsfw)
+            .unwrapOr(false));
+
+      let showPostNotifs = UserService.Instance.myUserInfo
+        .map(m => m.local_user_view.local_user.show_new_post_notifs)
+        .unwrapOr(false);
 
       // Only push these if you're on the first page, and you pass the nsfw check
       if (this.state.page == 1 && nsfwCheck) {
         // If you're on subscribed, only push it if you're subscribed.
         if (this.state.listingType == ListingType.Subscribed) {
           if (
-            UserService.Instance.myUserInfo.follows
+            UserService.Instance.myUserInfo
+              .map(m => m.follows)
+              .unwrapOr([])
               .map(c => c.community.id)
               .includes(data.post_view.community.id)
           ) {
             this.state.posts.unshift(data.post_view);
-            if (
-              UserService.Instance.myUserInfo?.local_user_view.local_user
-                .show_new_post_notifs
-            ) {
+            if (showPostNotifs) {
               notifyPost(data.post_view, this.context.router);
             }
           }
@@ -841,19 +783,13 @@ export class Home extends Component<any, HomeState> {
           // If you're on the local view, only push it if its local
           if (data.post_view.post.local) {
             this.state.posts.unshift(data.post_view);
-            if (
-              UserService.Instance.myUserInfo?.local_user_view.local_user
-                .show_new_post_notifs
-            ) {
+            if (showPostNotifs) {
               notifyPost(data.post_view, this.context.router);
             }
           }
         } else {
           this.state.posts.unshift(data.post_view);
-          if (
-            UserService.Instance.myUserInfo?.local_user_view.local_user
-              .show_new_post_notifs
-          ) {
+          if (showPostNotifs) {
             notifyPost(data.post_view, this.context.router);
           }
         }
@@ -867,39 +803,26 @@ export class Home extends Component<any, HomeState> {
       op == UserOperation.StickyPost ||
       op == UserOperation.SavePost
     ) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
       editPostFindRes(data.post_view, this.state.posts);
       this.setState(this.state);
     } else if (op == UserOperation.CreatePostLike) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
       createPostLikeFindRes(data.post_view, this.state.posts);
       this.setState(this.state);
     } else if (op == UserOperation.AddAdmin) {
-      let data = wsJsonToRes<AddAdminResponse>(msg).data;
+      let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
       this.state.siteRes.admins = data.admins;
       this.setState(this.state);
     } else if (op == UserOperation.BanPerson) {
-      let data = wsJsonToRes<BanPersonResponse>(msg).data;
-      let found = this.state.siteRes.banned.find(
-        p => (p.person.id = data.person_view.person.id)
-      );
-
-      // Remove the banned if its found in the list, and the action is an unban
-      if (found && !data.banned) {
-        this.state.siteRes.banned = this.state.siteRes.banned.filter(
-          i => i.person.id !== data.person_view.person.id
-        );
-      } else {
-        this.state.siteRes.banned.push(data.person_view);
-      }
-
+      let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
       this.state.posts
         .filter(p => p.creator.id == data.person_view.person.id)
         .forEach(p => (p.creator.banned = data.banned));
 
       this.setState(this.state);
     } else if (op == UserOperation.GetComments) {
-      let data = wsJsonToRes<GetCommentsResponse>(msg).data;
+      let data = wsJsonToRes<GetCommentsResponse>(msg, GetCommentsResponse);
       this.state.comments = data.comments;
       this.state.loading = false;
       this.setState(this.state);
@@ -908,18 +831,20 @@ export class Home extends Component<any, HomeState> {
       op == UserOperation.DeleteComment ||
       op == UserOperation.RemoveComment
     ) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       editCommentRes(data.comment_view, this.state.comments);
       this.setState(this.state);
     } else if (op == UserOperation.CreateComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
 
       // Necessary since it might be a user reply
       if (data.form_id) {
         // If you're on subscribed, only push it if you're subscribed.
         if (this.state.listingType == ListingType.Subscribed) {
           if (
-            UserService.Instance.myUserInfo.follows
+            UserService.Instance.myUserInfo
+              .map(m => m.follows)
+              .unwrapOr([])
               .map(c => c.community.id)
               .includes(data.comment_view.community.id)
           ) {
@@ -931,16 +856,37 @@ export class Home extends Component<any, HomeState> {
         this.setState(this.state);
       }
     } else if (op == UserOperation.SaveComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       saveCommentRes(data.comment_view, this.state.comments);
       this.setState(this.state);
     } else if (op == UserOperation.CreateCommentLike) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       createCommentLikeRes(data.comment_view, this.state.comments);
       this.setState(this.state);
     } else if (op == UserOperation.BlockPerson) {
-      let data = wsJsonToRes<BlockPersonResponse>(msg).data;
+      let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
       updatePersonBlock(data);
+    } else if (op == UserOperation.CreatePostReport) {
+      let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (op == UserOperation.CreateCommentReport) {
+      let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (
+      op == UserOperation.PurgePerson ||
+      op == UserOperation.PurgePost ||
+      op == UserOperation.PurgeComment ||
+      op == UserOperation.PurgeCommunity
+    ) {
+      let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+      if (data.success) {
+        toast(i18n.t("purge_success"));
+        this.context.router.history.push(`/`);
+      }
     }
   }
 }
index c9a7b1ff943f8df1af29b62d84b794f2bfd591dd..fe4064dec6a46cb05f9c96c33713e488e91aa6a6 100644 (file)
@@ -1,7 +1,8 @@
+import { None } from "@sniptt/monads";
 import { Component } from "inferno";
 import { GetSiteResponse } from "lemmy-js-client";
 import { i18n } from "../../i18next";
-import { setIsoData } from "../../utils";
+import { relTags, setIsoData } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 
 interface InstancesState {
@@ -20,54 +21,68 @@ export class Instances extends Component<any, InstancesState> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("instances")} - ${this.state.siteRes.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("instances")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
-    let federated_instances = this.state.siteRes?.federated_instances;
-    return (
-      federated_instances && (
+    return this.state.siteRes.federated_instances.match({
+      some: federated_instances => (
         <div class="container">
           <HtmlTags
             title={this.documentTitle}
             path={this.context.router.route.match.url}
+            description={None}
+            image={None}
           />
           <div class="row">
             <div class="col-md-6">
               <h5>{i18n.t("linked_instances")}</h5>
               {this.itemList(federated_instances.linked)}
             </div>
-            {federated_instances.allowed?.length > 0 && (
-              <div class="col-md-6">
-                <h5>{i18n.t("allowed_instances")}</h5>
-                {this.itemList(federated_instances.allowed)}
-              </div>
-            )}
-            {federated_instances.blocked?.length > 0 && (
-              <div class="col-md-6">
-                <h5>{i18n.t("blocked_instances")}</h5>
-                {this.itemList(federated_instances.blocked)}
-              </div>
-            )}
+            {federated_instances.allowed.match({
+              some: allowed =>
+                allowed.length > 0 && (
+                  <div class="col-md-6">
+                    <h5>{i18n.t("allowed_instances")}</h5>
+                    {this.itemList(allowed)}
+                  </div>
+                ),
+              none: <></>,
+            })}
+            {federated_instances.blocked.match({
+              some: blocked =>
+                blocked.length > 0 && (
+                  <div class="col-md-6">
+                    <h5>{i18n.t("blocked_instances")}</h5>
+                    {this.itemList(blocked)}
+                  </div>
+                ),
+              none: <></>,
+            })}
           </div>
         </div>
-      )
-    );
+      ),
+      none: <></>,
+    });
   }
 
   itemList(items: string[]) {
+    let noneFound = <div>{i18n.t("none_found")}</div>;
     return items.length > 0 ? (
       <ul>
         {items.map(i => (
           <li>
-            <a href={`https://${i}`} rel="noopener">
+            <a href={`https://${i}`} rel={relTags}>
               {i}
             </a>
           </li>
         ))}
       </ul>
     ) : (
-      <div>{i18n.t("none_found")}</div>
+      noneFound
     );
   }
 }
diff --git a/src/shared/components/home/legal.tsx b/src/shared/components/home/legal.tsx
new file mode 100644 (file)
index 0000000..590d7d8
--- /dev/null
@@ -0,0 +1,52 @@
+import { None } from "@sniptt/monads";
+import { Component } from "inferno";
+import { GetSiteResponse } from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { mdToHtml, setIsoData } from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+
+interface LegalState {
+  siteRes: GetSiteResponse;
+}
+
+export class Legal extends Component<any, LegalState> {
+  private isoData = setIsoData(this.context);
+  private emptyState: LegalState = {
+    siteRes: this.isoData.site_res,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+    this.state = this.emptyState;
+  }
+
+  get documentTitle(): string {
+    return i18n.t("legal_information");
+  }
+
+  render() {
+    return (
+      <div class="container">
+        <HtmlTags
+          title={this.documentTitle}
+          path={this.context.router.route.match.url}
+          description={None}
+          image={None}
+        />
+        {this.state.siteRes.site_view.match({
+          some: siteView =>
+            siteView.site.legal_information.match({
+              some: legal => (
+                <div
+                  className="md-div"
+                  dangerouslySetInnerHTML={mdToHtml(legal)}
+                />
+              ),
+              none: <></>,
+            }),
+          none: <></>,
+        })}
+      </div>
+    );
+  }
+}
index b227d64a9871ffe28fbdecd46a0bb03591f5004c..753e9d8166f9ba03b4df9e4ddd87ccfd93aba2ee 100644 (file)
@@ -1,66 +1,45 @@
+import { None } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
-import { T } from "inferno-i18next";
 import {
-  GetCaptchaResponse,
   GetSiteResponse,
   Login as LoginForm,
   LoginResponse,
   PasswordReset,
-  Register,
-  SiteView,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
   isBrowser,
-  joinLemmyUrl,
   setIsoData,
   toast,
   validEmail,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
-import { Icon, Spinner } from "../common/icon";
+import { Spinner } from "../common/icon";
 
 interface State {
   loginForm: LoginForm;
-  registerForm: Register;
   loginLoading: boolean;
-  registerLoading: boolean;
-  captcha: GetCaptchaResponse;
-  captchaPlaying: boolean;
-  site_view: SiteView;
+  siteRes: GetSiteResponse;
 }
 
 export class Login extends Component<any, State> {
   private isoData = setIsoData(this.context);
   private subscription: Subscription;
-  private audio: HTMLAudioElement;
 
   emptyState: State = {
-    loginForm: {
+    loginForm: new LoginForm({
       username_or_email: undefined,
       password: undefined,
-    },
-    registerForm: {
-      username: undefined,
-      password: undefined,
-      password_verify: undefined,
-      show_nsfw: false,
-      captcha_uuid: undefined,
-      captcha_answer: undefined,
-    },
+    }),
     loginLoading: false,
-    registerLoading: false,
-    captcha: undefined,
-    captchaPlaying: false,
-    site_view: this.isoData.site_res.site_view,
+    siteRes: this.isoData.site_res,
   };
 
   constructor(props: any, context: any) {
@@ -76,6 +55,13 @@ export class Login extends Component<any, State> {
     }
   }
 
+  componentDidMount() {
+    // Navigate to home if already logged in
+    if (UserService.Instance.myUserInfo.isSome()) {
+      this.context.router.history.push("/");
+    }
+  }
+
   componentWillUnmount() {
     if (isBrowser()) {
       this.subscription.unsubscribe();
@@ -83,7 +69,10 @@ export class Login extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("login")} - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("login")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   get isLemmyMl(): boolean {
@@ -96,10 +85,11 @@ export class Login extends Component<any, State> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         <div class="row">
-          <div class="col-12 col-lg-6 mb-4">{this.loginForm()}</div>
-          <div class="col-12 col-lg-6">{this.registerForm()}</div>
+          <div class="col-12 col-lg-6 offset-lg-3">{this.loginForm()}</div>
         </div>
       </div>
     );
@@ -168,187 +158,6 @@ export class Login extends Component<any, State> {
     );
   }
 
-  registerForm() {
-    return (
-      <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
-        <h5>{i18n.t("sign_up")}</h5>
-
-        <div class="form-group row">
-          <label class="col-sm-2 col-form-label" htmlFor="register-username">
-            {i18n.t("username")}
-          </label>
-
-          <div class="col-sm-10">
-            <input
-              type="text"
-              id="register-username"
-              class="form-control"
-              value={this.state.registerForm.username}
-              onInput={linkEvent(this, this.handleRegisterUsernameChange)}
-              required
-              minLength={3}
-              pattern="[a-zA-Z0-9_]+"
-            />
-          </div>
-        </div>
-
-        <div class="form-group row">
-          <label class="col-sm-2 col-form-label" htmlFor="register-email">
-            {i18n.t("email")}
-          </label>
-          <div class="col-sm-10">
-            <input
-              type="email"
-              id="register-email"
-              class="form-control"
-              placeholder={i18n.t("optional")}
-              value={this.state.registerForm.email}
-              autoComplete="email"
-              onInput={linkEvent(this, this.handleRegisterEmailChange)}
-              minLength={3}
-            />
-            {!validEmail(this.state.registerForm.email) && (
-              <div class="mt-2 mb-0 alert alert-light" role="alert">
-                <Icon icon="alert-triangle" classes="icon-inline mr-2" />
-                {i18n.t("no_password_reset")}
-              </div>
-            )}
-          </div>
-        </div>
-
-        <div class="form-group row">
-          <label class="col-sm-2 col-form-label" htmlFor="register-password">
-            {i18n.t("password")}
-          </label>
-          <div class="col-sm-10">
-            <input
-              type="password"
-              id="register-password"
-              value={this.state.registerForm.password}
-              autoComplete="new-password"
-              onInput={linkEvent(this, this.handleRegisterPasswordChange)}
-              maxLength={60}
-              class="form-control"
-              required
-            />
-          </div>
-        </div>
-
-        <div class="form-group row">
-          <label
-            class="col-sm-2 col-form-label"
-            htmlFor="register-verify-password"
-          >
-            {i18n.t("verify_password")}
-          </label>
-          <div class="col-sm-10">
-            <input
-              type="password"
-              id="register-verify-password"
-              value={this.state.registerForm.password_verify}
-              autoComplete="new-password"
-              onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
-              maxLength={60}
-              class="form-control"
-              required
-            />
-          </div>
-        </div>
-
-        {this.state.captcha && (
-          <div class="form-group row">
-            <label class="col-sm-2" htmlFor="register-captcha">
-              <span class="mr-2">{i18n.t("enter_code")}</span>
-              <button
-                type="button"
-                class="btn btn-secondary"
-                onClick={linkEvent(this, this.handleRegenCaptcha)}
-                aria-label={i18n.t("captcha")}
-              >
-                <Icon icon="refresh-cw" classes="icon-refresh-cw" />
-              </button>
-            </label>
-            {this.showCaptcha()}
-            <div class="col-sm-6">
-              <input
-                type="text"
-                class="form-control"
-                id="register-captcha"
-                value={this.state.registerForm.captcha_answer}
-                onInput={linkEvent(
-                  this,
-                  this.handleRegisterCaptchaAnswerChange
-                )}
-                required
-              />
-            </div>
-          </div>
-        )}
-        {this.state.site_view.site.enable_nsfw && (
-          <div class="form-group row">
-            <div class="col-sm-10">
-              <div class="form-check">
-                <input
-                  class="form-check-input"
-                  id="register-show-nsfw"
-                  type="checkbox"
-                  checked={this.state.registerForm.show_nsfw}
-                  onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
-                />
-                <label class="form-check-label" htmlFor="register-show-nsfw">
-                  {i18n.t("show_nsfw")}
-                </label>
-              </div>
-            </div>
-          </div>
-        )}
-        {this.isLemmyMl && (
-          <div class="mt-2 mb-0 alert alert-light" role="alert">
-            <T i18nKey="lemmy_ml_registration_message">
-              #<a href={joinLemmyUrl}>#</a>
-            </T>
-          </div>
-        )}
-        <div class="form-group row">
-          <div class="col-sm-10">
-            <button type="submit" class="btn btn-secondary">
-              {this.state.registerLoading ? <Spinner /> : i18n.t("sign_up")}
-            </button>
-          </div>
-        </div>
-      </form>
-    );
-  }
-
-  showCaptcha() {
-    return (
-      <div class="col-sm-4">
-        {this.state.captcha.ok && (
-          <>
-            <img
-              class="rounded-top img-fluid"
-              src={this.captchaPngSrc()}
-              style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
-              alt={i18n.t("captcha")}
-            />
-            {this.state.captcha.ok.wav && (
-              <button
-                class="rounded-bottom btn btn-sm btn-secondary btn-block"
-                style="border-top-right-radius: 0; border-top-left-radius: 0;"
-                title={i18n.t("play_captcha_audio")}
-                onClick={linkEvent(this, this.handleCaptchaPlay)}
-                type="button"
-                disabled={this.state.captchaPlaying}
-              >
-                <Icon icon="play" classes="icon-play" />
-              </button>
-            )}
-          </>
-        )}
-      </div>
-    );
-  }
-
   handleLoginSubmit(i: Login, event: any) {
     event.preventDefault();
     i.state.loginLoading = true;
@@ -366,83 +175,12 @@ export class Login extends Component<any, State> {
     i.setState(i.state);
   }
 
-  handleRegisterSubmit(i: Login, event: any) {
-    event.preventDefault();
-    i.state.registerLoading = true;
-    i.setState(i.state);
-    WebSocketService.Instance.send(wsClient.register(i.state.registerForm));
-  }
-
-  handleRegisterUsernameChange(i: Login, event: any) {
-    i.state.registerForm.username = event.target.value;
-    i.setState(i.state);
-  }
-
-  handleRegisterEmailChange(i: Login, event: any) {
-    i.state.registerForm.email = event.target.value;
-    if (i.state.registerForm.email == "") {
-      i.state.registerForm.email = undefined;
-    }
-    i.setState(i.state);
-  }
-
-  handleRegisterPasswordChange(i: Login, event: any) {
-    i.state.registerForm.password = event.target.value;
-    i.setState(i.state);
-  }
-
-  handleRegisterPasswordVerifyChange(i: Login, event: any) {
-    i.state.registerForm.password_verify = event.target.value;
-    i.setState(i.state);
-  }
-
-  handleRegisterShowNsfwChange(i: Login, event: any) {
-    i.state.registerForm.show_nsfw = event.target.checked;
-    i.setState(i.state);
-  }
-
-  handleRegisterCaptchaAnswerChange(i: Login, event: any) {
-    i.state.registerForm.captcha_answer = event.target.value;
-    i.setState(i.state);
-  }
-
-  handleRegenCaptcha(i: Login) {
-    i.audio = null;
-    i.state.captchaPlaying = false;
-    i.setState(i.state);
-    WebSocketService.Instance.send(wsClient.getCaptcha());
-  }
-
   handlePasswordReset(i: Login, event: any) {
     event.preventDefault();
-    let resetForm: PasswordReset = {
+    let resetForm = new PasswordReset({
       email: i.state.loginForm.username_or_email,
-    };
-    WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
-  }
-
-  handleCaptchaPlay(i: Login) {
-    // This was a bad bug, it should only build the new audio on a new file.
-    // Replays would stop prematurely if this was rebuilt every time.
-    if (i.audio == null) {
-      let base64 = `data:audio/wav;base64,${i.state.captcha.ok.wav}`;
-      i.audio = new Audio(base64);
-    }
-
-    i.audio.play();
-
-    i.state.captchaPlaying = true;
-    i.setState(i.state);
-
-    i.audio.addEventListener("ended", () => {
-      i.audio.currentTime = 0;
-      i.state.captchaPlaying = false;
-      i.setState(i.state);
     });
-  }
-
-  captchaPngSrc() {
-    return `data:image/png;base64,${this.state.captcha.ok.png}`;
+    WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
   }
 
   parseMessage(msg: any) {
@@ -451,47 +189,19 @@ export class Login extends Component<any, State> {
     if (msg.error) {
       toast(i18n.t(msg.error), "danger");
       this.state = this.emptyState;
-      this.state.registerForm.captcha_answer = undefined;
-      // Refetch another captcha
-      WebSocketService.Instance.send(wsClient.getCaptcha());
       this.setState(this.state);
       return;
     } else {
       if (op == UserOperation.Login) {
-        let data = wsJsonToRes<LoginResponse>(msg).data;
-        this.state = this.emptyState;
-        this.setState(this.state);
-        UserService.Instance.login(data);
-        WebSocketService.Instance.send(
-          wsClient.userJoin({
-            auth: authField(),
-          })
-        );
-        toast(i18n.t("logged_in"));
-        this.props.history.push("/");
-      } else if (op == UserOperation.Register) {
-        let data = wsJsonToRes<LoginResponse>(msg).data;
+        let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
         this.state = this.emptyState;
         this.setState(this.state);
         UserService.Instance.login(data);
-        WebSocketService.Instance.send(
-          wsClient.userJoin({
-            auth: authField(),
-          })
-        );
-        this.props.history.push("/communities");
-      } else if (op == UserOperation.GetCaptcha) {
-        let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
-        if (data.ok) {
-          this.state.captcha = data;
-          this.state.registerForm.captcha_uuid = data.ok.uuid;
-          this.setState(this.state);
-        }
       } else if (op == UserOperation.PasswordReset) {
         toast(i18n.t("reset_password_mail_sent"));
       } else if (op == UserOperation.GetSite) {
-        let data = wsJsonToRes<GetSiteResponse>(msg).data;
-        this.state.site_view = data.site_view;
+        let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+        this.state.siteRes = data;
         this.setState(this.state);
       }
     }
index eef59bd00d8a3fe2f0ef4d0289b3dd0c5b119531..46d225e24639db3b75077fcc73ce9c12f106f239 100644 (file)
@@ -1,11 +1,19 @@
+import { None, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Helmet } from "inferno-helmet";
-import { LoginResponse, Register, UserOperation } from "lemmy-js-client";
+import {
+  LoginResponse,
+  Register,
+  toUndefined,
+  UserOperation,
+  wsJsonToRes,
+  wsUserOp,
+} from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { delay, retryWhen, take } from "rxjs/operators";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
-import { toast, wsClient, wsJsonToRes, wsUserOp } from "../../utils";
+import { toast, wsClient } from "../../utils";
 import { Spinner } from "../common/icon";
 import { SiteForm } from "./site-form";
 
@@ -19,16 +27,19 @@ export class Setup extends Component<any, State> {
   private subscription: Subscription;
 
   private emptyState: State = {
-    userForm: {
+    userForm: new Register({
       username: undefined,
       password: undefined,
       password_verify: undefined,
       show_nsfw: true,
       // The first admin signup doesn't need a captcha
-      captcha_uuid: "",
-      captcha_answer: "",
-    },
-    doneRegisteringUser: false,
+      captcha_uuid: None,
+      captcha_answer: None,
+      email: None,
+      honeypot: None,
+      answer: None,
+    }),
+    doneRegisteringUser: UserService.Instance.myUserInfo.isSome(),
     userLoading: false,
   };
 
@@ -64,7 +75,7 @@ export class Setup extends Component<any, State> {
             {!this.state.doneRegisteringUser ? (
               this.registerUser()
             ) : (
-              <SiteForm />
+              <SiteForm site={None} showLocal />
             )}
           </div>
         </div>
@@ -104,7 +115,7 @@ export class Setup extends Component<any, State> {
               id="email"
               class="form-control"
               placeholder={i18n.t("optional")}
-              value={this.state.userForm.email}
+              value={toUndefined(this.state.userForm.email)}
               onInput={linkEvent(this, this.handleRegisterEmailChange)}
               minLength={3}
             />
@@ -122,6 +133,8 @@ export class Setup extends Component<any, State> {
               onInput={linkEvent(this, this.handleRegisterPasswordChange)}
               class="form-control"
               required
+              autoComplete="new-password"
+              minLength={10}
               maxLength={60}
             />
           </div>
@@ -138,6 +151,8 @@ export class Setup extends Component<any, State> {
               onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
               class="form-control"
               required
+              autoComplete="new-password"
+              minLength={10}
               maxLength={60}
             />
           </div>
@@ -167,7 +182,7 @@ export class Setup extends Component<any, State> {
   }
 
   handleRegisterEmailChange(i: Setup, event: any) {
-    i.state.userForm.email = event.target.value;
+    i.state.userForm.email = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -189,9 +204,8 @@ export class Setup extends Component<any, State> {
       this.setState(this.state);
       return;
     } else if (op == UserOperation.Register) {
-      let data = wsJsonToRes<LoginResponse>(msg).data;
+      let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
       this.state.userLoading = false;
-      this.state.doneRegisteringUser = true;
       UserService.Instance.login(data);
       this.setState(this.state);
     } else if (op == UserOperation.CreateSite) {
diff --git a/src/shared/components/home/signup.tsx b/src/shared/components/home/signup.tsx
new file mode 100644 (file)
index 0000000..9e6e3c7
--- /dev/null
@@ -0,0 +1,570 @@
+import { None, Option, Some } from "@sniptt/monads";
+import { Options, passwordStrength } from "check-password-strength";
+import { I18nKeys } from "i18next";
+import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next-dess";
+import {
+  CaptchaResponse,
+  GetCaptchaResponse,
+  GetSiteResponse,
+  LoginResponse,
+  Register,
+  SiteView,
+  toUndefined,
+  UserOperation,
+  wsJsonToRes,
+  wsUserOp,
+} from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
+import {
+  isBrowser,
+  joinLemmyUrl,
+  mdToHtml,
+  setIsoData,
+  toast,
+  validEmail,
+  wsClient,
+  wsSubscribe,
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Icon, Spinner } from "../common/icon";
+import { MarkdownTextArea } from "../common/markdown-textarea";
+
+const passwordStrengthOptions: Options<string> = [
+  {
+    id: 0,
+    value: "very_weak",
+    minDiversity: 0,
+    minLength: 0,
+  },
+  {
+    id: 1,
+    value: "weak",
+    minDiversity: 2,
+    minLength: 10,
+  },
+  {
+    id: 2,
+    value: "medium",
+    minDiversity: 3,
+    minLength: 12,
+  },
+  {
+    id: 3,
+    value: "strong",
+    minDiversity: 4,
+    minLength: 14,
+  },
+];
+
+interface State {
+  registerForm: Register;
+  registerLoading: boolean;
+  captcha: Option<GetCaptchaResponse>;
+  captchaPlaying: boolean;
+  siteRes: GetSiteResponse;
+}
+
+export class Signup extends Component<any, State> {
+  private isoData = setIsoData(this.context);
+  private subscription: Subscription;
+  private audio: HTMLAudioElement;
+
+  emptyState: State = {
+    registerForm: new Register({
+      username: undefined,
+      password: undefined,
+      password_verify: undefined,
+      show_nsfw: false,
+      captcha_uuid: None,
+      captcha_answer: None,
+      honeypot: None,
+      answer: None,
+      email: None,
+    }),
+    registerLoading: false,
+    captcha: None,
+    captchaPlaying: false,
+    siteRes: this.isoData.site_res,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+
+    this.state = this.emptyState;
+    this.handleAnswerChange = this.handleAnswerChange.bind(this);
+
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
+    if (isBrowser()) {
+      WebSocketService.Instance.send(wsClient.getCaptcha());
+    }
+  }
+
+  componentWillUnmount() {
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
+  }
+
+  get documentTitle(): string {
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${this.titleName(siteView)} - ${siteView.site.name}`,
+      none: "",
+    });
+  }
+
+  titleName(siteView: SiteView): string {
+    return i18n.t(siteView.site.private_instance ? "apply_to_join" : "sign_up");
+  }
+
+  get isLemmyMl(): boolean {
+    return isBrowser() && window.location.hostname == "lemmy.ml";
+  }
+
+  render() {
+    return (
+      <div class="container">
+        <HtmlTags
+          title={this.documentTitle}
+          path={this.context.router.route.match.url}
+          description={None}
+          image={None}
+        />
+        <div class="row">
+          <div class="col-12 col-lg-6 offset-lg-3">{this.registerForm()}</div>
+        </div>
+      </div>
+    );
+  }
+
+  registerForm() {
+    return this.state.siteRes.site_view.match({
+      some: siteView => (
+        <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
+          <h5>{this.titleName(siteView)}</h5>
+
+          {this.isLemmyMl && (
+            <div class="form-group row">
+              <div class="mt-2 mb-0 alert alert-warning" role="alert">
+                <T i18nKey="lemmy_ml_registration_message">
+                  #<a href={joinLemmyUrl}>#</a>
+                </T>
+              </div>
+            </div>
+          )}
+
+          <div class="form-group row">
+            <label class="col-sm-2 col-form-label" htmlFor="register-username">
+              {i18n.t("username")}
+            </label>
+
+            <div class="col-sm-10">
+              <input
+                type="text"
+                id="register-username"
+                class="form-control"
+                value={this.state.registerForm.username}
+                onInput={linkEvent(this, this.handleRegisterUsernameChange)}
+                required
+                minLength={3}
+                pattern="[a-zA-Z0-9_]+"
+                title={i18n.t("community_reqs")}
+              />
+            </div>
+          </div>
+
+          <div class="form-group row">
+            <label class="col-sm-2 col-form-label" htmlFor="register-email">
+              {i18n.t("email")}
+            </label>
+            <div class="col-sm-10">
+              <input
+                type="email"
+                id="register-email"
+                class="form-control"
+                placeholder={
+                  siteView.site.require_email_verification
+                    ? i18n.t("required")
+                    : i18n.t("optional")
+                }
+                value={toUndefined(this.state.registerForm.email)}
+                autoComplete="email"
+                onInput={linkEvent(this, this.handleRegisterEmailChange)}
+                required={siteView.site.require_email_verification}
+                minLength={3}
+              />
+              {!siteView.site.require_email_verification &&
+                !this.state.registerForm.email
+                  .map(validEmail)
+                  .unwrapOr(true) && (
+                  <div class="mt-2 mb-0 alert alert-warning" role="alert">
+                    <Icon icon="alert-triangle" classes="icon-inline mr-2" />
+                    {i18n.t("no_password_reset")}
+                  </div>
+                )}
+            </div>
+          </div>
+
+          <div class="form-group row">
+            <label class="col-sm-2 col-form-label" htmlFor="register-password">
+              {i18n.t("password")}
+            </label>
+            <div class="col-sm-10">
+              <input
+                type="password"
+                id="register-password"
+                value={this.state.registerForm.password}
+                autoComplete="new-password"
+                onInput={linkEvent(this, this.handleRegisterPasswordChange)}
+                minLength={10}
+                maxLength={60}
+                class="form-control"
+                required
+              />
+              {this.state.registerForm.password && (
+                <div class={this.passwordColorClass}>
+                  {i18n.t(this.passwordStrength as I18nKeys)}
+                </div>
+              )}
+            </div>
+          </div>
+
+          <div class="form-group row">
+            <label
+              class="col-sm-2 col-form-label"
+              htmlFor="register-verify-password"
+            >
+              {i18n.t("verify_password")}
+            </label>
+            <div class="col-sm-10">
+              <input
+                type="password"
+                id="register-verify-password"
+                value={this.state.registerForm.password_verify}
+                autoComplete="new-password"
+                onInput={linkEvent(
+                  this,
+                  this.handleRegisterPasswordVerifyChange
+                )}
+                maxLength={60}
+                class="form-control"
+                required
+              />
+            </div>
+          </div>
+
+          {siteView.site.require_application && (
+            <>
+              <div class="form-group row">
+                <div class="offset-sm-2 col-sm-10">
+                  <div class="mt-2 alert alert-warning" role="alert">
+                    <Icon icon="alert-triangle" classes="icon-inline mr-2" />
+                    {i18n.t("fill_out_application")}
+                  </div>
+                  {siteView.site.application_question.match({
+                    some: question => (
+                      <div
+                        className="md-div"
+                        dangerouslySetInnerHTML={mdToHtml(question)}
+                      />
+                    ),
+                    none: <></>,
+                  })}
+                </div>
+              </div>
+
+              <div class="form-group row">
+                <label
+                  class="col-sm-2 col-form-label"
+                  htmlFor="application_answer"
+                >
+                  {i18n.t("answer")}
+                </label>
+                <div class="col-sm-10">
+                  <MarkdownTextArea
+                    initialContent={None}
+                    placeholder={None}
+                    buttonTitle={None}
+                    maxLength={None}
+                    onContentChange={this.handleAnswerChange}
+                    hideNavigationWarnings
+                  />
+                </div>
+              </div>
+            </>
+          )}
+
+          {this.state.captcha.isSome() && (
+            <div class="form-group row">
+              <label class="col-sm-2" htmlFor="register-captcha">
+                <span class="mr-2">{i18n.t("enter_code")}</span>
+                <button
+                  type="button"
+                  class="btn btn-secondary"
+                  onClick={linkEvent(this, this.handleRegenCaptcha)}
+                  aria-label={i18n.t("captcha")}
+                >
+                  <Icon icon="refresh-cw" classes="icon-refresh-cw" />
+                </button>
+              </label>
+              {this.showCaptcha()}
+              <div class="col-sm-6">
+                <input
+                  type="text"
+                  class="form-control"
+                  id="register-captcha"
+                  value={toUndefined(this.state.registerForm.captcha_answer)}
+                  onInput={linkEvent(
+                    this,
+                    this.handleRegisterCaptchaAnswerChange
+                  )}
+                  required
+                />
+              </div>
+            </div>
+          )}
+          {siteView.site.enable_nsfw && (
+            <div class="form-group row">
+              <div class="col-sm-10">
+                <div class="form-check">
+                  <input
+                    class="form-check-input"
+                    id="register-show-nsfw"
+                    type="checkbox"
+                    checked={this.state.registerForm.show_nsfw}
+                    onChange={linkEvent(
+                      this,
+                      this.handleRegisterShowNsfwChange
+                    )}
+                  />
+                  <label class="form-check-label" htmlFor="register-show-nsfw">
+                    {i18n.t("show_nsfw")}
+                  </label>
+                </div>
+              </div>
+            </div>
+          )}
+          <input
+            tabIndex={-1}
+            autoComplete="false"
+            name="a_password"
+            type="text"
+            class="form-control honeypot"
+            id="register-honey"
+            value={toUndefined(this.state.registerForm.honeypot)}
+            onInput={linkEvent(this, this.handleHoneyPotChange)}
+          />
+          <div class="form-group row">
+            <div class="col-sm-10">
+              <button type="submit" class="btn btn-secondary">
+                {this.state.registerLoading ? (
+                  <Spinner />
+                ) : (
+                  this.titleName(siteView)
+                )}
+              </button>
+            </div>
+          </div>
+        </form>
+      ),
+      none: <></>,
+    });
+  }
+
+  showCaptcha() {
+    return this.state.captcha.match({
+      some: captcha => (
+        <div class="col-sm-4">
+          {captcha.ok.match({
+            some: res => (
+              <>
+                <img
+                  class="rounded-top img-fluid"
+                  src={this.captchaPngSrc(res)}
+                  style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
+                  alt={i18n.t("captcha")}
+                />
+                {res.wav.isSome() && (
+                  <button
+                    class="rounded-bottom btn btn-sm btn-secondary btn-block"
+                    style="border-top-right-radius: 0; border-top-left-radius: 0;"
+                    title={i18n.t("play_captcha_audio")}
+                    onClick={linkEvent(this, this.handleCaptchaPlay)}
+                    type="button"
+                    disabled={this.state.captchaPlaying}
+                  >
+                    <Icon icon="play" classes="icon-play" />
+                  </button>
+                )}
+              </>
+            ),
+            none: <></>,
+          })}
+        </div>
+      ),
+      none: <></>,
+    });
+  }
+
+  get passwordStrength() {
+    return passwordStrength(
+      this.state.registerForm.password,
+      passwordStrengthOptions
+    ).value;
+  }
+
+  get passwordColorClass(): string {
+    let strength = this.passwordStrength;
+
+    if (["weak", "medium"].includes(strength)) {
+      return "text-warning";
+    } else if (strength == "strong") {
+      return "text-success";
+    } else {
+      return "text-danger";
+    }
+  }
+
+  handleRegisterSubmit(i: Signup, event: any) {
+    event.preventDefault();
+    i.state.registerLoading = true;
+    i.setState(i.state);
+    WebSocketService.Instance.send(wsClient.register(i.state.registerForm));
+  }
+
+  handleRegisterUsernameChange(i: Signup, event: any) {
+    i.state.registerForm.username = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterEmailChange(i: Signup, event: any) {
+    i.state.registerForm.email = Some(event.target.value);
+    if (i.state.registerForm.email.unwrap() == "") {
+      i.state.registerForm.email = None;
+    }
+    i.setState(i.state);
+  }
+
+  handleRegisterPasswordChange(i: Signup, event: any) {
+    i.state.registerForm.password = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterPasswordVerifyChange(i: Signup, event: any) {
+    i.state.registerForm.password_verify = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterShowNsfwChange(i: Signup, event: any) {
+    i.state.registerForm.show_nsfw = event.target.checked;
+    i.setState(i.state);
+  }
+
+  handleRegisterCaptchaAnswerChange(i: Signup, event: any) {
+    i.state.registerForm.captcha_answer = Some(event.target.value);
+    i.setState(i.state);
+  }
+
+  handleAnswerChange(val: string) {
+    this.state.registerForm.answer = Some(val);
+    this.setState(this.state);
+  }
+
+  handleHoneyPotChange(i: Signup, event: any) {
+    i.state.registerForm.honeypot = Some(event.target.value);
+    i.setState(i.state);
+  }
+
+  handleRegenCaptcha(i: Signup) {
+    i.audio = null;
+    i.state.captchaPlaying = false;
+    i.setState(i.state);
+    WebSocketService.Instance.send(wsClient.getCaptcha());
+  }
+
+  handleCaptchaPlay(i: Signup) {
+    // This was a bad bug, it should only build the new audio on a new file.
+    // Replays would stop prematurely if this was rebuilt every time.
+    i.state.captcha.match({
+      some: captcha =>
+        captcha.ok.match({
+          some: res => {
+            if (i.audio == null) {
+              let base64 = `data:audio/wav;base64,${res.wav}`;
+              i.audio = new Audio(base64);
+            }
+
+            i.audio.play();
+
+            i.state.captchaPlaying = true;
+            i.setState(i.state);
+
+            i.audio.addEventListener("ended", () => {
+              i.audio.currentTime = 0;
+              i.state.captchaPlaying = false;
+              i.setState(i.state);
+            });
+          },
+          none: void 0,
+        }),
+      none: void 0,
+    });
+  }
+
+  captchaPngSrc(captcha: CaptchaResponse) {
+    return `data:image/png;base64,${captcha.png}`;
+  }
+
+  parseMessage(msg: any) {
+    let op = wsUserOp(msg);
+    console.log(msg);
+    if (msg.error) {
+      toast(i18n.t(msg.error), "danger");
+      this.state = this.emptyState;
+      this.state.registerForm.captcha_answer = undefined;
+      // Refetch another captcha
+      // WebSocketService.Instance.send(wsClient.getCaptcha());
+      this.setState(this.state);
+      return;
+    } else {
+      if (op == UserOperation.Register) {
+        let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
+        this.state = this.emptyState;
+        this.setState(this.state);
+        // Only log them in if a jwt was set
+        if (data.jwt.isSome()) {
+          UserService.Instance.login(data);
+          this.props.history.push("/communities");
+        } else {
+          if (data.verify_email_sent) {
+            toast(i18n.t("verify_email_sent"));
+          }
+          if (data.registration_created) {
+            toast(i18n.t("registration_application_sent"));
+          }
+          this.props.history.push("/");
+        }
+      } else if (op == UserOperation.GetCaptcha) {
+        let data = wsJsonToRes<GetCaptchaResponse>(msg, GetCaptchaResponse);
+        data.ok.match({
+          some: res => {
+            this.state.captcha = Some(data);
+            this.state.registerForm.captcha_uuid = Some(res.uuid);
+            this.setState(this.state);
+          },
+          none: void 0,
+        });
+      } else if (op == UserOperation.PasswordReset) {
+        toast(i18n.t("reset_password_mail_sent"));
+      } else if (op == UserOperation.GetSite) {
+        let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
+        this.state.siteRes = data;
+        this.setState(this.state);
+      }
+    }
+  }
+}
index 6bfed4279009852c57938a0433bc2c26a8973398..5602d9bf13a4b37881b5cba31456ba50b6e14d5a 100644 (file)
@@ -1,41 +1,63 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
-import { CreateSite, EditSite, Site } from "lemmy-js-client";
+import {
+  CreateSite,
+  EditSite,
+  ListingType,
+  Site,
+  toUndefined,
+} from "lemmy-js-client";
 import { i18n } from "../../i18next";
 import { WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
-  randomStr,
+  fetchThemeList,
   wsClient,
 } from "../../utils";
 import { Spinner } from "../common/icon";
 import { ImageUploadForm } from "../common/image-upload-form";
+import { ListingTypeSelect } from "../common/listing-type-select";
 import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface SiteFormProps {
-  site?: Site; // If a site is given, that means this is an edit
-  onCancel?(): any;
+  site: Option<Site>; // If a site is given, that means this is an edit
+  showLocal?: boolean;
+  onCancel?(): void;
+  onEdit?(): void;
 }
 
 interface SiteFormState {
   siteForm: EditSite;
   loading: boolean;
+  themeList: Option<string[]>;
 }
 
 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
-  private id = `site-form-${randomStr()}`;
   private emptyState: SiteFormState = {
-    siteForm: {
-      enable_downvotes: true,
-      open_registration: true,
-      enable_nsfw: true,
-      name: null,
-      icon: null,
-      banner: null,
-      auth: authField(),
-    },
+    siteForm: new EditSite({
+      enable_downvotes: Some(true),
+      open_registration: Some(true),
+      enable_nsfw: Some(true),
+      name: None,
+      icon: None,
+      banner: None,
+      require_email_verification: None,
+      require_application: None,
+      application_question: None,
+      private_instance: None,
+      default_theme: None,
+      sidebar: None,
+      default_post_listing_type: None,
+      legal_information: None,
+      description: None,
+      community_creation_admin_only: None,
+      auth: undefined,
+      hide_modlog_mod_names: Some(true),
+    }),
     loading: false,
+    themeList: None,
   };
 
   constructor(props: any, context: any) {
@@ -43,6 +65,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
 
     this.state = this.emptyState;
     this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
+    this.handleSiteLegalInfoChange = this.handleSiteLegalInfoChange.bind(this);
+    this.handleSiteApplicationQuestionChange =
+      this.handleSiteApplicationQuestionChange.bind(this);
 
     this.handleIconUpload = this.handleIconUpload.bind(this);
     this.handleIconRemove = this.handleIconRemove.bind(this);
@@ -50,21 +75,41 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
     this.handleBannerUpload = this.handleBannerUpload.bind(this);
     this.handleBannerRemove = this.handleBannerRemove.bind(this);
 
-    if (this.props.site) {
-      this.state.siteForm = {
-        name: this.props.site.name,
-        sidebar: this.props.site.sidebar,
-        description: this.props.site.description,
-        enable_downvotes: this.props.site.enable_downvotes,
-        open_registration: this.props.site.open_registration,
-        enable_nsfw: this.props.site.enable_nsfw,
-        community_creation_admin_only:
-          this.props.site.community_creation_admin_only,
-        icon: this.props.site.icon,
-        banner: this.props.site.banner,
-        auth: authField(),
-      };
-    }
+    this.handleDefaultPostListingTypeChange =
+      this.handleDefaultPostListingTypeChange.bind(this);
+
+    this.props.site.match({
+      some: site => {
+        this.state.siteForm = new EditSite({
+          name: Some(site.name),
+          sidebar: site.sidebar,
+          description: site.description,
+          enable_downvotes: Some(site.enable_downvotes),
+          open_registration: Some(site.open_registration),
+          enable_nsfw: Some(site.enable_nsfw),
+          community_creation_admin_only: Some(
+            site.community_creation_admin_only
+          ),
+          icon: site.icon,
+          banner: site.banner,
+          require_email_verification: Some(site.require_email_verification),
+          require_application: Some(site.require_application),
+          application_question: site.application_question,
+          private_instance: Some(site.private_instance),
+          default_theme: Some(site.default_theme),
+          default_post_listing_type: Some(site.default_post_listing_type),
+          legal_information: site.legal_information,
+          hide_modlog_mod_names: site.hide_modlog_mod_names,
+          auth: undefined,
+        });
+      },
+      none: void 0,
+    });
+  }
+
+  async componentDidMount() {
+    this.state.themeList = Some(await fetchThemeList());
+    this.setState(this.state);
   }
 
   // Necessary to stop the loading
@@ -76,9 +121,10 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   componentDidUpdate() {
     if (
       !this.state.loading &&
-      !this.props.site &&
+      this.props.site.isNone() &&
       (this.state.siteForm.name ||
         this.state.siteForm.sidebar ||
+        this.state.siteForm.application_question ||
         this.state.siteForm.description)
     ) {
       window.onbeforeunload = () => true;
@@ -97,16 +143,17 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
         <Prompt
           when={
             !this.state.loading &&
-            !this.props.site &&
+            this.props.site.isNone() &&
             (this.state.siteForm.name ||
               this.state.siteForm.sidebar ||
+              this.state.siteForm.application_question ||
               this.state.siteForm.description)
           }
           message={i18n.t("block_leaving")}
         />
         <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
           <h5>{`${
-            this.props.site
+            this.props.site.isSome()
               ? capitalizeFirstLetter(i18n.t("save"))
               : capitalizeFirstLetter(i18n.t("name"))
           } ${i18n.t("your_site")}`}</h5>
@@ -119,7 +166,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
                 type="text"
                 id="create-site-name"
                 class="form-control"
-                value={this.state.siteForm.name}
+                value={toUndefined(this.state.siteForm.name)}
                 onInput={linkEvent(this, this.handleSiteNameChange)}
                 required
                 minLength={3}
@@ -155,24 +202,57 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
                 type="text"
                 class="form-control"
                 id="site-desc"
-                value={this.state.siteForm.description}
+                value={toUndefined(this.state.siteForm.description)}
                 onInput={linkEvent(this, this.handleSiteDescChange)}
                 maxLength={150}
               />
             </div>
           </div>
           <div class="form-group row">
-            <label class="col-12 col-form-label" htmlFor={this.id}>
-              {i18n.t("sidebar")}
-            </label>
+            <label class="col-12 col-form-label">{i18n.t("sidebar")}</label>
             <div class="col-12">
               <MarkdownTextArea
                 initialContent={this.state.siteForm.sidebar}
+                placeholder={None}
+                buttonTitle={None}
+                maxLength={None}
                 onContentChange={this.handleSiteSidebarChange}
                 hideNavigationWarnings
               />
             </div>
           </div>
+          <div class="form-group row">
+            <label class="col-12 col-form-label">
+              {i18n.t("legal_information")}
+            </label>
+            <div class="col-12">
+              <MarkdownTextArea
+                initialContent={this.state.siteForm.legal_information}
+                placeholder={None}
+                buttonTitle={None}
+                maxLength={None}
+                onContentChange={this.handleSiteLegalInfoChange}
+                hideNavigationWarnings
+              />
+            </div>
+          </div>
+          {this.state.siteForm.require_application.unwrapOr(false) && (
+            <div class="form-group row">
+              <label class="col-12 col-form-label">
+                {i18n.t("application_questionnaire")}
+              </label>
+              <div class="col-12">
+                <MarkdownTextArea
+                  initialContent={this.state.siteForm.application_question}
+                  placeholder={None}
+                  buttonTitle={None}
+                  maxLength={None}
+                  onContentChange={this.handleSiteApplicationQuestionChange}
+                  hideNavigationWarnings
+                />
+              </div>
+            </div>
+          )}
           <div class="form-group row">
             <div class="col-12">
               <div class="form-check">
@@ -180,7 +260,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
                   class="form-check-input"
                   id="create-site-downvotes"
                   type="checkbox"
-                  checked={this.state.siteForm.enable_downvotes}
+                  checked={toUndefined(this.state.siteForm.enable_downvotes)}
                   onChange={linkEvent(
                     this,
                     this.handleSiteEnableDownvotesChange
@@ -199,7 +279,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
                   class="form-check-input"
                   id="create-site-enable-nsfw"
                   type="checkbox"
-                  checked={this.state.siteForm.enable_nsfw}
+                  checked={toUndefined(this.state.siteForm.enable_nsfw)}
                   onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
                 />
                 <label
@@ -218,7 +298,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
                   class="form-check-input"
                   id="create-site-open-registration"
                   type="checkbox"
-                  checked={this.state.siteForm.open_registration}
+                  checked={toUndefined(this.state.siteForm.open_registration)}
                   onChange={linkEvent(
                     this,
                     this.handleSiteOpenRegistrationChange
@@ -240,7 +320,9 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
                   class="form-check-input"
                   id="create-site-community-creation-admin-only"
                   type="checkbox"
-                  checked={this.state.siteForm.community_creation_admin_only}
+                  checked={toUndefined(
+                    this.state.siteForm.community_creation_admin_only
+                  )}
                   onChange={linkEvent(
                     this,
                     this.handleSiteCommunityCreationAdminOnly
@@ -255,6 +337,129 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
               </div>
             </div>
           </div>
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-require-email-verification"
+                  type="checkbox"
+                  checked={toUndefined(
+                    this.state.siteForm.require_email_verification
+                  )}
+                  onChange={linkEvent(
+                    this,
+                    this.handleSiteRequireEmailVerification
+                  )}
+                />
+                <label
+                  class="form-check-label"
+                  htmlFor="create-site-require-email-verification"
+                >
+                  {i18n.t("require_email_verification")}
+                </label>
+              </div>
+            </div>
+          </div>
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-require-application"
+                  type="checkbox"
+                  checked={toUndefined(this.state.siteForm.require_application)}
+                  onChange={linkEvent(this, this.handleSiteRequireApplication)}
+                />
+                <label
+                  class="form-check-label"
+                  htmlFor="create-site-require-application"
+                >
+                  {i18n.t("require_registration_application")}
+                </label>
+              </div>
+            </div>
+          </div>
+          <div class="form-group row">
+            <div class="col-12">
+              <label
+                class="form-check-label mr-2"
+                htmlFor="create-site-default-theme"
+              >
+                {i18n.t("theme")}
+              </label>
+              <select
+                id="create-site-default-theme"
+                value={toUndefined(this.state.siteForm.default_theme)}
+                onChange={linkEvent(this, this.handleSiteDefaultTheme)}
+                class="custom-select w-auto"
+              >
+                <option value="browser">{i18n.t("browser_default")}</option>
+                {this.state.themeList.unwrapOr([]).map(theme => (
+                  <option value={theme}>{theme}</option>
+                ))}
+              </select>
+            </div>
+          </div>
+          {this.props.showLocal && (
+            <form className="form-group row">
+              <label class="col-sm-3">{i18n.t("listing_type")}</label>
+              <div class="col-sm-9">
+                <ListingTypeSelect
+                  type_={
+                    ListingType[
+                      this.state.siteForm.default_post_listing_type.unwrapOr(
+                        "Local"
+                      )
+                    ]
+                  }
+                  showLocal
+                  showSubscribed={false}
+                  onChange={this.handleDefaultPostListingTypeChange}
+                />
+              </div>
+            </form>
+          )}
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-private-instance"
+                  type="checkbox"
+                  checked={toUndefined(this.state.siteForm.private_instance)}
+                  onChange={linkEvent(this, this.handleSitePrivateInstance)}
+                />
+                <label
+                  class="form-check-label"
+                  htmlFor="create-site-private-instance"
+                >
+                  {i18n.t("private_instance")}
+                </label>
+              </div>
+            </div>
+          </div>
+          <div class="form-group row">
+            <div class="col-12">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="create-site-hide-modlog-mod-names"
+                  type="checkbox"
+                  checked={toUndefined(
+                    this.state.siteForm.hide_modlog_mod_names
+                  )}
+                  onChange={linkEvent(this, this.handleSiteHideModlogModNames)}
+                />
+                <label
+                  class="form-check-label"
+                  htmlFor="create-site-hide-modlog-mod-names"
+                >
+                  {i18n.t("hide_modlog_mod_names")}
+                </label>
+              </div>
+            </div>
+          </div>
           <div class="form-group row">
             <div class="col-12">
               <button
@@ -264,13 +469,13 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
               >
                 {this.state.loading ? (
                   <Spinner />
-                ) : this.props.site ? (
+                ) : this.props.site.isSome() ? (
                   capitalizeFirstLetter(i18n.t("save"))
                 ) : (
                   capitalizeFirstLetter(i18n.t("create"))
                 )}
               </button>
-              {this.props.site && (
+              {this.props.site.isSome() && (
                 <button
                   type="button"
                   class="btn btn-secondary"
@@ -289,50 +494,104 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   handleCreateSiteSubmit(i: SiteForm, event: any) {
     event.preventDefault();
     i.state.loading = true;
-    if (i.props.site) {
+    i.state.siteForm.auth = auth().unwrap();
+
+    if (i.props.site.isSome()) {
       WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
+      i.props.onEdit();
     } else {
-      let form: CreateSite = {
-        name: i.state.siteForm.name || "My site",
-        ...i.state.siteForm,
-      };
+      let sForm = i.state.siteForm;
+      let form = new CreateSite({
+        name: sForm.name.unwrapOr("My site"),
+        sidebar: sForm.sidebar,
+        description: sForm.description,
+        icon: sForm.icon,
+        banner: sForm.banner,
+        community_creation_admin_only: sForm.community_creation_admin_only,
+        enable_nsfw: sForm.enable_nsfw,
+        enable_downvotes: sForm.enable_downvotes,
+        require_application: sForm.require_application,
+        application_question: sForm.application_question,
+        open_registration: sForm.open_registration,
+        require_email_verification: sForm.require_email_verification,
+        private_instance: sForm.private_instance,
+        default_theme: sForm.default_theme,
+        default_post_listing_type: sForm.default_post_listing_type,
+        auth: auth().unwrap(),
+        hide_modlog_mod_names: sForm.hide_modlog_mod_names,
+      });
       WebSocketService.Instance.send(wsClient.createSite(form));
     }
     i.setState(i.state);
   }
 
   handleSiteNameChange(i: SiteForm, event: any) {
-    i.state.siteForm.name = event.target.value;
+    i.state.siteForm.name = Some(event.target.value);
     i.setState(i.state);
   }
 
   handleSiteSidebarChange(val: string) {
-    this.state.siteForm.sidebar = val;
+    this.state.siteForm.sidebar = Some(val);
+    this.setState(this.state);
+  }
+
+  handleSiteLegalInfoChange(val: string) {
+    this.state.siteForm.legal_information = Some(val);
+    this.setState(this.state);
+  }
+
+  handleSiteApplicationQuestionChange(val: string) {
+    this.state.siteForm.application_question = Some(val);
     this.setState(this.state);
   }
 
   handleSiteDescChange(i: SiteForm, event: any) {
-    i.state.siteForm.description = event.target.value;
+    i.state.siteForm.description = Some(event.target.value);
     i.setState(i.state);
   }
 
   handleSiteEnableNsfwChange(i: SiteForm, event: any) {
-    i.state.siteForm.enable_nsfw = event.target.checked;
+    i.state.siteForm.enable_nsfw = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
-    i.state.siteForm.open_registration = event.target.checked;
+    i.state.siteForm.open_registration = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
-    i.state.siteForm.community_creation_admin_only = event.target.checked;
+    i.state.siteForm.community_creation_admin_only = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
-    i.state.siteForm.enable_downvotes = event.target.checked;
+    i.state.siteForm.enable_downvotes = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteRequireApplication(i: SiteForm, event: any) {
+    i.state.siteForm.require_application = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteRequireEmailVerification(i: SiteForm, event: any) {
+    i.state.siteForm.require_email_verification = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSitePrivateInstance(i: SiteForm, event: any) {
+    i.state.siteForm.private_instance = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteHideModlogModNames(i: SiteForm, event: any) {
+    i.state.siteForm.hide_modlog_mod_names = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleSiteDefaultTheme(i: SiteForm, event: any) {
+    i.state.siteForm.default_theme = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -341,22 +600,29 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
   }
 
   handleIconUpload(url: string) {
-    this.state.siteForm.icon = url;
+    this.state.siteForm.icon = Some(url);
     this.setState(this.state);
   }
 
   handleIconRemove() {
-    this.state.siteForm.icon = "";
+    this.state.siteForm.icon = Some("");
     this.setState(this.state);
   }
 
   handleBannerUpload(url: string) {
-    this.state.siteForm.banner = url;
+    this.state.siteForm.banner = Some(url);
     this.setState(this.state);
   }
 
   handleBannerRemove() {
-    this.state.siteForm.banner = "";
+    this.state.siteForm.banner = Some("");
+    this.setState(this.state);
+  }
+
+  handleDefaultPostListingTypeChange(val: ListingType) {
+    this.state.siteForm.default_post_listing_type = Some(
+      ListingType[ListingType[val]]
+    );
     this.setState(this.state);
   }
 }
diff --git a/src/shared/components/home/site-sidebar.tsx b/src/shared/components/home/site-sidebar.tsx
new file mode 100644 (file)
index 0000000..79a8a43
--- /dev/null
@@ -0,0 +1,267 @@
+import { None, Option, Some } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
+import { Link } from "inferno-router";
+import { PersonViewSafe, Site, SiteAggregates } from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { amAdmin, mdToHtml, numToSI } from "../../utils";
+import { BannerIconHeader } from "../common/banner-icon-header";
+import { Icon } from "../common/icon";
+import { PersonListing } from "../person/person-listing";
+import { SiteForm } from "./site-form";
+
+interface SiteSidebarProps {
+  site: Site;
+  showLocal: boolean;
+  counts: Option<SiteAggregates>;
+  admins: Option<PersonViewSafe[]>;
+  online: Option<number>;
+}
+
+interface SiteSidebarState {
+  collapsed: boolean;
+  showEdit: boolean;
+}
+
+export class SiteSidebar extends Component<SiteSidebarProps, SiteSidebarState> {
+  private emptyState: SiteSidebarState = {
+    collapsed: false,
+    showEdit: false,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+    this.state = this.emptyState;
+    this.handleEditCancel = this.handleEditCancel.bind(this);
+    this.handleEditSite = this.handleEditSite.bind(this);
+  }
+
+  render() {
+    let site = this.props.site;
+    return (
+      <div class="card border-secondary mb-3">
+        <div class="card-body">
+          {!this.state.showEdit ? (
+            <div>
+              <div class="mb-2">
+                {this.siteName()}
+                {this.props.admins.isSome() && this.adminButtons()}
+              </div>
+              {!this.state.collapsed && (
+                <>
+                  <BannerIconHeader banner={site.banner} icon={None} />
+                  {this.siteInfo()}
+                </>
+              )}
+            </div>
+          ) : (
+            <SiteForm
+              site={Some(site)}
+              showLocal={this.props.showLocal}
+              onEdit={this.handleEditSite}
+              onCancel={this.handleEditCancel}
+            />
+          )}
+        </div>
+      </div>
+    );
+  }
+
+  siteName() {
+    let site = this.props.site;
+    return (
+      <h5 class="mb-0 d-inline">
+        {site.name}
+        <button
+          class="btn btn-sm text-muted"
+          onClick={linkEvent(this, this.handleCollapseSidebar)}
+          aria-label={i18n.t("collapse")}
+          data-tippy-content={i18n.t("collapse")}
+        >
+          {this.state.collapsed ? (
+            <Icon icon="plus-square" classes="icon-inline" />
+          ) : (
+            <Icon icon="minus-square" classes="icon-inline" />
+          )}
+        </button>
+      </h5>
+    );
+  }
+
+  siteInfo() {
+    let site = this.props.site;
+    return (
+      <div>
+        {site.description.match({
+          some: description => <h6>{description}</h6>,
+          none: <></>,
+        })}
+        {site.sidebar.match({
+          some: sidebar => this.siteSidebar(sidebar),
+          none: <></>,
+        })}
+        {this.props.counts.match({
+          some: counts => this.badges(counts),
+          none: <></>,
+        })}
+        {this.props.admins.match({
+          some: admins => this.admins(admins),
+          none: <></>,
+        })}
+      </div>
+    );
+  }
+
+  adminButtons() {
+    return (
+      amAdmin(this.props.admins) && (
+        <ul class="list-inline mb-1 text-muted font-weight-bold">
+          <li className="list-inline-item-action">
+            <button
+              class="btn btn-link d-inline-block text-muted"
+              onClick={linkEvent(this, this.handleEditClick)}
+              aria-label={i18n.t("edit")}
+              data-tippy-content={i18n.t("edit")}
+            >
+              <Icon icon="edit" classes="icon-inline" />
+            </button>
+          </li>
+        </ul>
+      )
+    );
+  }
+
+  siteSidebar(sidebar: string) {
+    return (
+      <div className="md-div" dangerouslySetInnerHTML={mdToHtml(sidebar)} />
+    );
+  }
+
+  admins(admins: PersonViewSafe[]) {
+    return (
+      <ul class="mt-1 list-inline small mb-0">
+        <li class="list-inline-item">{i18n.t("admins")}:</li>
+        {admins.map(av => (
+          <li class="list-inline-item">
+            <PersonListing person={av.person} />
+          </li>
+        ))}
+      </ul>
+    );
+  }
+
+  badges(siteAggregates: SiteAggregates) {
+    let counts = siteAggregates;
+    let online = this.props.online.unwrapOr(1);
+    return (
+      <ul class="my-2 list-inline">
+        <li className="list-inline-item badge badge-secondary">
+          {i18n.t("number_online", {
+            count: online,
+            formattedCount: numToSI(online),
+          })}
+        </li>
+        <li
+          className="list-inline-item badge badge-secondary pointer"
+          data-tippy-content={i18n.t("active_users_in_the_last_day", {
+            count: counts.users_active_day,
+            formattedCount: numToSI(counts.users_active_day),
+          })}
+        >
+          {i18n.t("number_of_users", {
+            count: counts.users_active_day,
+            formattedCount: numToSI(counts.users_active_day),
+          })}{" "}
+          / {i18n.t("day")}
+        </li>
+        <li
+          className="list-inline-item badge badge-secondary pointer"
+          data-tippy-content={i18n.t("active_users_in_the_last_week", {
+            count: counts.users_active_week,
+            formattedCount: counts.users_active_week,
+          })}
+        >
+          {i18n.t("number_of_users", {
+            count: counts.users_active_week,
+            formattedCount: numToSI(counts.users_active_week),
+          })}{" "}
+          / {i18n.t("week")}
+        </li>
+        <li
+          className="list-inline-item badge badge-secondary pointer"
+          data-tippy-content={i18n.t("active_users_in_the_last_month", {
+            count: counts.users_active_month,
+            formattedCount: counts.users_active_month,
+          })}
+        >
+          {i18n.t("number_of_users", {
+            count: counts.users_active_month,
+            formattedCount: numToSI(counts.users_active_month),
+          })}{" "}
+          / {i18n.t("month")}
+        </li>
+        <li
+          className="list-inline-item badge badge-secondary pointer"
+          data-tippy-content={i18n.t("active_users_in_the_last_six_months", {
+            count: counts.users_active_half_year,
+            formattedCount: counts.users_active_half_year,
+          })}
+        >
+          {i18n.t("number_of_users", {
+            count: counts.users_active_half_year,
+            formattedCount: numToSI(counts.users_active_half_year),
+          })}{" "}
+          / {i18n.t("number_of_months", { count: 6, formattedCount: 6 })}
+        </li>
+        <li className="list-inline-item badge badge-secondary">
+          {i18n.t("number_of_users", {
+            count: counts.users,
+            formattedCount: numToSI(counts.users),
+          })}
+        </li>
+        <li className="list-inline-item badge badge-secondary">
+          {i18n.t("number_of_communities", {
+            count: counts.communities,
+            formattedCount: numToSI(counts.communities),
+          })}
+        </li>
+        <li className="list-inline-item badge badge-secondary">
+          {i18n.t("number_of_posts", {
+            count: counts.posts,
+            formattedCount: numToSI(counts.posts),
+          })}
+        </li>
+        <li className="list-inline-item badge badge-secondary">
+          {i18n.t("number_of_comments", {
+            count: counts.comments,
+            formattedCount: numToSI(counts.comments),
+          })}
+        </li>
+        <li className="list-inline-item">
+          <Link className="badge badge-primary" to="/modlog">
+            {i18n.t("modlog")}
+          </Link>
+        </li>
+      </ul>
+    );
+  }
+
+  handleCollapseSidebar(i: SiteSidebar) {
+    i.state.collapsed = !i.state.collapsed;
+    i.setState(i.state);
+  }
+
+  handleEditClick(i: SiteSidebar) {
+    i.state.showEdit = true;
+    i.setState(i.state);
+  }
+
+  handleEditSite() {
+    this.state.showEdit = false;
+    this.setState(this.state);
+  }
+
+  handleEditCancel() {
+    this.state.showEdit = false;
+    this.setState(this.state);
+  }
+}
index 2e8527d1fceee3cdc5efbaa2654981417a1289bf..e8192d27caa21963f3203d428313e7839d726ab5 100644 (file)
@@ -1,38 +1,52 @@
-import { Component } from "inferno";
+import { None, Option, Some } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
+  AdminPurgeCommentView,
+  AdminPurgeCommunityView,
+  AdminPurgePersonView,
+  AdminPurgePostView,
   CommunityModeratorView,
   GetCommunity,
   GetCommunityResponse,
   GetModlog,
   GetModlogResponse,
+  GetSiteResponse,
   ModAddCommunityView,
   ModAddView,
   ModBanFromCommunityView,
   ModBanView,
   ModLockPostView,
+  ModlogActionType,
   ModRemoveCommentView,
   ModRemoveCommunityView,
   ModRemovePostView,
   ModStickyPostView,
   ModTransferCommunityView,
-  SiteView,
+  PersonSafe,
+  toUndefined,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import moment from "moment";
 import { Subscription } from "rxjs";
 import { i18n } from "../i18next";
 import { InitialFetchRequest } from "../interfaces";
-import { UserService, WebSocketService } from "../services";
+import { WebSocketService } from "../services";
 import {
+  amAdmin,
+  amMod,
+  auth,
+  choicesModLogConfig,
+  debounce,
   fetchLimit,
+  fetchUsers,
   isBrowser,
   setIsoData,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../utils";
 import { HtmlTags } from "./common/html-tags";
 import { Spinner } from "./common/icon";
@@ -40,23 +54,10 @@ import { MomentTime } from "./common/moment-time";
 import { Paginator } from "./common/paginator";
 import { CommunityLink } from "./community/community-link";
 import { PersonListing } from "./person/person-listing";
-
-enum ModlogEnum {
-  ModRemovePost,
-  ModLockPost,
-  ModStickyPost,
-  ModRemoveComment,
-  ModRemoveCommunity,
-  ModBanFromCommunity,
-  ModAddCommunity,
-  ModTransferCommunity,
-  ModAdd,
-  ModBan,
-}
-
 type ModlogType = {
   id: number;
-  type_: ModlogEnum;
+  type_: ModlogActionType;
+  moderator: Option<PersonSafe>;
   view:
     | ModRemovePostView
     | ModLockPostView
@@ -67,69 +68,87 @@ type ModlogType = {
     | ModBanView
     | ModAddCommunityView
     | ModTransferCommunityView
-    | ModAddView;
+    | ModAddView
+    | AdminPurgePersonView
+    | AdminPurgeCommunityView
+    | AdminPurgePostView
+    | AdminPurgeCommentView;
   when_: string;
 };
+var Choices: any;
+if (isBrowser()) {
+  Choices = require("choices.js");
+}
 
 interface ModlogState {
-  res: GetModlogResponse;
-  communityId?: number;
-  communityName?: string;
-  communityMods?: CommunityModeratorView[];
+  res: Option<GetModlogResponse>;
+  communityId: Option<number>;
+  communityMods: Option<CommunityModeratorView[]>;
+  communityName: Option<string>;
   page: number;
-  site_view: SiteView;
+  siteRes: GetSiteResponse;
   loading: boolean;
+  filter_action: ModlogActionType;
+  filter_user: Option<number>;
+  filter_mod: Option<number>;
 }
 
 export class Modlog extends Component<any, ModlogState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(
+    this.context,
+    GetModlogResponse,
+    GetCommunityResponse
+  );
   private subscription: Subscription;
+  private userChoices: any;
+  private modChoices: any;
   private emptyState: ModlogState = {
-    res: {
-      removed_posts: [],
-      locked_posts: [],
-      stickied_posts: [],
-      removed_comments: [],
-      removed_communities: [],
-      banned_from_community: [],
-      banned: [],
-      added_to_community: [],
-      transferred_to_community: [],
-      added: [],
-    },
+    res: None,
+    communityId: None,
+    communityMods: None,
+    communityName: None,
     page: 1,
     loading: true,
-    site_view: this.isoData.site_res.site_view,
+    siteRes: this.isoData.site_res,
+    filter_action: ModlogActionType.All,
+    filter_user: None,
+    filter_mod: None,
   };
-
   constructor(props: any, context: any) {
     super(props, context);
-
     this.state = this.emptyState;
     this.handlePageChange = this.handlePageChange.bind(this);
 
     this.state.communityId = this.props.match.params.community_id
-      ? Number(this.props.match.params.community_id)
-      : undefined;
+      ? Some(Number(this.props.match.params.community_id))
+      : None;
 
     this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      let data = this.isoData.routeData[0];
-      this.state.res = data;
-      this.state.loading = false;
+      this.state.res = Some(this.isoData.routeData[0] as GetModlogResponse);
 
-      // Getting the moderators
       if (this.isoData.routeData[1]) {
-        this.state.communityMods = this.isoData.routeData[1].moderators;
+        // Getting the moderators
+        let communityRes = Some(
+          this.isoData.routeData[1] as GetCommunityResponse
+        );
+        this.state.communityMods = communityRes.map(c => c.moderators);
       }
+
+      this.state.loading = false;
     } else {
       this.refetch();
     }
   }
 
+  componentDidMount() {
+    this.setupUserFilter();
+    this.setupModFilter();
+  }
+
   componentWillUnmount() {
     if (isBrowser()) {
       this.subscription.unsubscribe();
@@ -139,77 +158,121 @@ export class Modlog extends Component<any, ModlogState> {
   buildCombined(res: GetModlogResponse): ModlogType[] {
     let removed_posts: ModlogType[] = res.removed_posts.map(r => ({
       id: r.mod_remove_post.id,
-      type_: ModlogEnum.ModRemovePost,
+      type_: ModlogActionType.ModRemovePost,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_remove_post.when_,
     }));
 
     let locked_posts: ModlogType[] = res.locked_posts.map(r => ({
       id: r.mod_lock_post.id,
-      type_: ModlogEnum.ModLockPost,
+      type_: ModlogActionType.ModLockPost,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_lock_post.when_,
     }));
 
     let stickied_posts: ModlogType[] = res.stickied_posts.map(r => ({
       id: r.mod_sticky_post.id,
-      type_: ModlogEnum.ModStickyPost,
+      type_: ModlogActionType.ModStickyPost,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_sticky_post.when_,
     }));
 
     let removed_comments: ModlogType[] = res.removed_comments.map(r => ({
       id: r.mod_remove_comment.id,
-      type_: ModlogEnum.ModRemoveComment,
+      type_: ModlogActionType.ModRemoveComment,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_remove_comment.when_,
     }));
 
     let removed_communities: ModlogType[] = res.removed_communities.map(r => ({
       id: r.mod_remove_community.id,
-      type_: ModlogEnum.ModRemoveCommunity,
+      type_: ModlogActionType.ModRemoveCommunity,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_remove_community.when_,
     }));
 
     let banned_from_community: ModlogType[] = res.banned_from_community.map(
       r => ({
         id: r.mod_ban_from_community.id,
-        type_: ModlogEnum.ModBanFromCommunity,
+        type_: ModlogActionType.ModBanFromCommunity,
         view: r,
+        moderator: r.moderator,
         when_: r.mod_ban_from_community.when_,
       })
     );
 
     let added_to_community: ModlogType[] = res.added_to_community.map(r => ({
       id: r.mod_add_community.id,
-      type_: ModlogEnum.ModAddCommunity,
+      type_: ModlogActionType.ModAddCommunity,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_add_community.when_,
     }));
 
     let transferred_to_community: ModlogType[] =
       res.transferred_to_community.map(r => ({
         id: r.mod_transfer_community.id,
-        type_: ModlogEnum.ModTransferCommunity,
+        type_: ModlogActionType.ModTransferCommunity,
         view: r,
+        moderator: r.moderator,
         when_: r.mod_transfer_community.when_,
       }));
 
     let added: ModlogType[] = res.added.map(r => ({
       id: r.mod_add.id,
-      type_: ModlogEnum.ModAdd,
+      type_: ModlogActionType.ModAdd,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_add.when_,
     }));
 
     let banned: ModlogType[] = res.banned.map(r => ({
       id: r.mod_ban.id,
-      type_: ModlogEnum.ModBan,
+      type_: ModlogActionType.ModBan,
       view: r,
+      moderator: r.moderator,
       when_: r.mod_ban.when_,
     }));
 
+    let purged_persons: ModlogType[] = res.admin_purged_persons.map(r => ({
+      id: r.admin_purge_person.id,
+      type_: ModlogActionType.AdminPurgePerson,
+      view: r,
+      moderator: r.admin,
+      when_: r.admin_purge_person.when_,
+    }));
+
+    let purged_communities: ModlogType[] = res.admin_purged_communities.map(
+      r => ({
+        id: r.admin_purge_community.id,
+        type_: ModlogActionType.AdminPurgeCommunity,
+        view: r,
+        moderator: r.admin,
+        when_: r.admin_purge_community.when_,
+      })
+    );
+
+    let purged_posts: ModlogType[] = res.admin_purged_posts.map(r => ({
+      id: r.admin_purge_post.id,
+      type_: ModlogActionType.AdminPurgePost,
+      view: r,
+      moderator: r.admin,
+      when_: r.admin_purge_post.when_,
+    }));
+
+    let purged_comments: ModlogType[] = res.admin_purged_comments.map(r => ({
+      id: r.admin_purge_comment.id,
+      type_: ModlogActionType.AdminPurgeComment,
+      view: r,
+      moderator: r.admin,
+      when_: r.admin_purge_comment.when_,
+    }));
+
     let combined: ModlogType[] = [];
 
     combined.push(...removed_posts);
@@ -222,12 +285,10 @@ export class Modlog extends Component<any, ModlogState> {
     combined.push(...transferred_to_community);
     combined.push(...added);
     combined.push(...banned);
-
-    if (this.state.communityId && combined.length > 0) {
-      this.state.communityName = (
-        combined[0].view as ModRemovePostView
-      ).community.name;
-    }
+    combined.push(...purged_persons);
+    combined.push(...purged_communities);
+    combined.push(...purged_posts);
+    combined.push(...purged_comments);
 
     // Sort them by time
     combined.sort((a, b) => b.when_.localeCompare(a.when_));
@@ -237,39 +298,47 @@ export class Modlog extends Component<any, ModlogState> {
 
   renderModlogType(i: ModlogType) {
     switch (i.type_) {
-      case ModlogEnum.ModRemovePost: {
+      case ModlogActionType.ModRemovePost: {
         let mrpv = i.view as ModRemovePostView;
         return [
-          mrpv.mod_remove_post.removed ? "Removed " : "Restored ",
+          mrpv.mod_remove_post.removed.unwrapOr(false)
+            ? "Removed "
+            : "Restored ",
           <span>
             Post <Link to={`/post/${mrpv.post.id}`}>{mrpv.post.name}</Link>
           </span>,
-          mrpv.mod_remove_post.reason &&
-            ` reason: ${mrpv.mod_remove_post.reason}`,
+          mrpv.mod_remove_post.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
         ];
       }
-      case ModlogEnum.ModLockPost: {
+      case ModlogActionType.ModLockPost: {
         let mlpv = i.view as ModLockPostView;
         return [
-          mlpv.mod_lock_post.locked ? "Locked " : "Unlocked ",
+          mlpv.mod_lock_post.locked.unwrapOr(false) ? "Locked " : "Unlocked ",
           <span>
             Post <Link to={`/post/${mlpv.post.id}`}>{mlpv.post.name}</Link>
           </span>,
         ];
       }
-      case ModlogEnum.ModStickyPost: {
+      case ModlogActionType.ModStickyPost: {
         let mspv = i.view as ModStickyPostView;
         return [
-          mspv.mod_sticky_post.stickied ? "Stickied " : "Unstickied ",
+          mspv.mod_sticky_post.stickied.unwrapOr(false)
+            ? "Stickied "
+            : "Unstickied ",
           <span>
             Post <Link to={`/post/${mspv.post.id}`}>{mspv.post.name}</Link>
           </span>,
         ];
       }
-      case ModlogEnum.ModRemoveComment: {
+      case ModlogActionType.ModRemoveComment: {
         let mrc = i.view as ModRemoveCommentView;
         return [
-          mrc.mod_remove_comment.removed ? "Removed " : "Restored ",
+          mrc.mod_remove_comment.removed.unwrapOr(false)
+            ? "Removed "
+            : "Restored ",
           <span>
             Comment{" "}
             <Link to={`/post/${mrc.post.id}/comment/${mrc.comment.id}`}>
@@ -280,30 +349,40 @@ export class Modlog extends Component<any, ModlogState> {
             {" "}
             by <PersonListing person={mrc.commenter} />
           </span>,
-          mrc.mod_remove_comment.reason &&
-            ` reason: ${mrc.mod_remove_comment.reason}`,
+          mrc.mod_remove_comment.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
         ];
       }
-      case ModlogEnum.ModRemoveCommunity: {
+      case ModlogActionType.ModRemoveCommunity: {
         let mrco = i.view as ModRemoveCommunityView;
         return [
-          mrco.mod_remove_community.removed ? "Removed " : "Restored ",
+          mrco.mod_remove_community.removed.unwrapOr(false)
+            ? "Removed "
+            : "Restored ",
           <span>
             Community <CommunityLink community={mrco.community} />
           </span>,
-          mrco.mod_remove_community.reason &&
-            ` reason: ${mrco.mod_remove_community.reason}`,
-          mrco.mod_remove_community.expires &&
-            ` expires: ${moment
-              .utc(mrco.mod_remove_community.expires)
-              .fromNow()}`,
+          mrco.mod_remove_community.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+          mrco.mod_remove_community.expires.match({
+            some: expires => (
+              <div>expires: {moment.utc(expires).fromNow()}</div>
+            ),
+            none: <></>,
+          }),
         ];
       }
-      case ModlogEnum.ModBanFromCommunity: {
+      case ModlogActionType.ModBanFromCommunity: {
         let mbfc = i.view as ModBanFromCommunityView;
         return [
           <span>
-            {mbfc.mod_ban_from_community.banned ? "Banned " : "Unbanned "}{" "}
+            {mbfc.mod_ban_from_community.banned.unwrapOr(false)
+              ? "Banned "
+              : "Unbanned "}{" "}
           </span>,
           <span>
             <PersonListing person={mbfc.banned_person} />
@@ -312,23 +391,25 @@ export class Modlog extends Component<any, ModlogState> {
           <span>
             <CommunityLink community={mbfc.community} />
           </span>,
-          <div>
-            {mbfc.mod_ban_from_community.reason &&
-              ` reason: ${mbfc.mod_ban_from_community.reason}`}
-          </div>,
-          <div>
-            {mbfc.mod_ban_from_community.expires &&
-              ` expires: ${moment
-                .utc(mbfc.mod_ban_from_community.expires)
-                .fromNow()}`}
-          </div>,
+          mbfc.mod_ban_from_community.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+          mbfc.mod_ban_from_community.expires.match({
+            some: expires => (
+              <div>expires: {moment.utc(expires).fromNow()}</div>
+            ),
+            none: <></>,
+          }),
         ];
       }
-      case ModlogEnum.ModAddCommunity: {
+      case ModlogActionType.ModAddCommunity: {
         let mac = i.view as ModAddCommunityView;
         return [
           <span>
-            {mac.mod_add_community.removed ? "Removed " : "Appointed "}{" "}
+            {mac.mod_add_community.removed.unwrapOr(false)
+              ? "Removed "
+              : "Appointed "}{" "}
           </span>,
           <span>
             <PersonListing person={mac.modded_person} />
@@ -339,11 +420,13 @@ export class Modlog extends Component<any, ModlogState> {
           </span>,
         ];
       }
-      case ModlogEnum.ModTransferCommunity: {
+      case ModlogActionType.ModTransferCommunity: {
         let mtc = i.view as ModTransferCommunityView;
         return [
           <span>
-            {mtc.mod_transfer_community.removed ? "Removed " : "Transferred "}{" "}
+            {mtc.mod_transfer_community.removed.unwrapOr(false)
+              ? "Removed "
+              : "Transferred "}{" "}
           </span>,
           <span>
             <CommunityLink community={mtc.community} />
@@ -354,50 +437,103 @@ export class Modlog extends Component<any, ModlogState> {
           </span>,
         ];
       }
-      case ModlogEnum.ModBan: {
+      case ModlogActionType.ModBan: {
         let mb = i.view as ModBanView;
         return [
-          <span>{mb.mod_ban.banned ? "Banned " : "Unbanned "} </span>,
+          <span>
+            {mb.mod_ban.banned.unwrapOr(false) ? "Banned " : "Unbanned "}{" "}
+          </span>,
           <span>
             <PersonListing person={mb.banned_person} />
           </span>,
-          <div>{mb.mod_ban.reason && ` reason: ${mb.mod_ban.reason}`}</div>,
-          <div>
-            {mb.mod_ban.expires &&
-              ` expires: ${moment.utc(mb.mod_ban.expires).fromNow()}`}
-          </div>,
+          mb.mod_ban.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+          mb.mod_ban.expires.match({
+            some: expires => (
+              <div>expires: {moment.utc(expires).fromNow()}</div>
+            ),
+            none: <></>,
+          }),
         ];
       }
-      case ModlogEnum.ModAdd: {
+      case ModlogActionType.ModAdd: {
         let ma = i.view as ModAddView;
         return [
-          <span>{ma.mod_add.removed ? "Removed " : "Appointed "} </span>,
+          <span>
+            {ma.mod_add.removed.unwrapOr(false) ? "Removed " : "Appointed "}{" "}
+          </span>,
           <span>
             <PersonListing person={ma.modded_person} />
           </span>,
           <span> as an admin </span>,
         ];
       }
+      case ModlogActionType.AdminPurgePerson: {
+        let ap = i.view as AdminPurgePersonView;
+        return [
+          <span>Purged a Person</span>,
+          ap.admin_purge_person.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+        ];
+      }
+      case ModlogActionType.AdminPurgeCommunity: {
+        let ap = i.view as AdminPurgeCommunityView;
+        return [
+          <span>Purged a Community</span>,
+          ap.admin_purge_community.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+        ];
+      }
+      case ModlogActionType.AdminPurgePost: {
+        let ap = i.view as AdminPurgePostView;
+        return [
+          <span>Purged a Post from from </span>,
+          <CommunityLink community={ap.community} />,
+          ap.admin_purge_post.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+        ];
+      }
+      case ModlogActionType.AdminPurgeComment: {
+        let ap = i.view as AdminPurgeCommentView;
+        return [
+          <span>
+            Purged a Comment from{" "}
+            <Link to={`/post/${ap.post.id}`}>{ap.post.name}</Link>
+          </span>,
+          ap.admin_purge_comment.reason.match({
+            some: reason => <div>reason: {reason}</div>,
+            none: <></>,
+          }),
+        ];
+      }
       default:
         return <div />;
     }
   }
 
   combined() {
-    let combined = this.buildCombined(this.state.res);
+    let combined = this.state.res.map(this.buildCombined).unwrapOr([]);
 
     return (
       <tbody>
         {combined.map(i => (
           <tr>
             <td>
-              <MomentTime data={i} />
+              <MomentTime published={i.when_} updated={None} />
             </td>
             <td>
-              {this.isAdminOrMod ? (
-                <PersonListing person={i.view.moderator} />
+              {this.amAdminOrMod ? (
+                <PersonListing person={i.moderator.unwrap()} />
               ) : (
-                <div>{i18n.t("mod")}</div>
+                <div>{this.modOrAdminText(i.moderator)}</div>
               )}
             </td>
             <td>{this.renderModlogType(i)}</td>
@@ -407,31 +543,38 @@ export class Modlog extends Component<any, ModlogState> {
     );
   }
 
-  get isAdminOrMod(): boolean {
-    let isAdmin =
-      UserService.Instance.myUserInfo &&
-      this.isoData.site_res.admins
-        .map(a => a.person.id)
-        .includes(UserService.Instance.myUserInfo.local_user_view.person.id);
-    let isMod =
-      UserService.Instance.myUserInfo &&
-      this.state.communityMods &&
-      this.state.communityMods
-        .map(m => m.moderator.id)
-        .includes(UserService.Instance.myUserInfo.local_user_view.person.id);
-    return isAdmin || isMod;
+  get amAdminOrMod(): boolean {
+    return (
+      amAdmin(Some(this.state.siteRes.admins)) ||
+      amMod(this.state.communityMods)
+    );
+  }
+
+  modOrAdminText(person: Option<PersonSafe>): string {
+    return person.match({
+      some: res =>
+        this.isoData.site_res.admins.map(a => a.person.id).includes(res.id)
+          ? i18n.t("admin")
+          : i18n.t("mod"),
+      none: i18n.t("mod"),
+    });
   }
 
   get documentTitle(): string {
-    return `Modlog - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `Modlog - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
     return (
-      <div class="container">
+      <div className="container">
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         {this.state.loading ? (
           <h5>
@@ -440,19 +583,80 @@ export class Modlog extends Component<any, ModlogState> {
         ) : (
           <div>
             <h5>
-              {this.state.communityName && (
-                <Link
-                  className="text-body"
-                  to={`/c/${this.state.communityName}`}
-                >
-                  /c/{this.state.communityName}{" "}
-                </Link>
-              )}
+              {this.state.communityName.match({
+                some: name => (
+                  <Link className="text-body" to={`/c/${name}`}>
+                    /c/{name}{" "}
+                  </Link>
+                ),
+                none: <></>,
+              })}
               <span>{i18n.t("modlog")}</span>
             </h5>
-            <div class="table-responsive">
-              <table id="modlog_table" class="table table-sm table-hover">
-                <thead class="pointer">
+            <form className="form-inline mr-2">
+              <select
+                value={this.state.filter_action}
+                onChange={linkEvent(this, this.handleFilterActionChange)}
+                className="custom-select col-4 mb-2"
+                aria-label="action"
+              >
+                <option disabled aria-hidden="true">
+                  {i18n.t("filter_by_action")}
+                </option>
+                <option value={ModlogActionType.All}>{i18n.t("all")}</option>
+                <option value={ModlogActionType.ModRemovePost}>
+                  Removing Posts
+                </option>
+                <option value={ModlogActionType.ModLockPost}>
+                  Locking Posts
+                </option>
+                <option value={ModlogActionType.ModStickyPost}>
+                  Stickying Posts
+                </option>
+                <option value={ModlogActionType.ModRemoveComment}>
+                  Removing Comments
+                </option>
+                <option value={ModlogActionType.ModRemoveCommunity}>
+                  Removing Communities
+                </option>
+                <option value={ModlogActionType.ModBanFromCommunity}>
+                  Banning From Communities
+                </option>
+                <option value={ModlogActionType.ModAddCommunity}>
+                  Adding Mod to Community
+                </option>
+                <option value={ModlogActionType.ModTransferCommunity}>
+                  Transfering Communities
+                </option>
+                <option value={ModlogActionType.ModAdd}>
+                  Adding Mod to Site
+                </option>
+                <option value={ModlogActionType.ModBan}>
+                  Banning From Site
+                </option>
+              </select>
+              {this.state.siteRes.site_view.match({
+                some: site_view =>
+                  !site_view.site.hide_modlog_mod_names.unwrapOr(false) && (
+                    <select
+                      id="filter-mod"
+                      value={toUndefined(this.state.filter_mod)}
+                    >
+                      <option>{i18n.t("filter_by_mod")}</option>
+                    </select>
+                  ),
+                none: <></>,
+              })}
+              <select
+                id="filter-user"
+                value={toUndefined(this.state.filter_user)}
+              >
+                <option>{i18n.t("filter_by_user")}</option>
+              </select>
+            </form>
+            <div className="table-responsive">
+              <table id="modlog_table" className="table table-sm table-hover">
+                <thead className="pointer">
                   <tr>
                     <th> {i18n.t("time")}</th>
                     <th>{i18n.t("mod")}</th>
@@ -472,49 +676,147 @@ export class Modlog extends Component<any, ModlogState> {
     );
   }
 
+  handleFilterActionChange(i: Modlog, event: any) {
+    i.setState({ filter_action: event.target.value });
+    i.refetch();
+  }
+
   handlePageChange(val: number) {
     this.setState({ page: val });
     this.refetch();
   }
 
   refetch() {
-    let modlogForm: GetModlog = {
+    let modlogForm = new GetModlog({
       community_id: this.state.communityId,
-      page: this.state.page,
-      limit: fetchLimit,
-    };
+      page: Some(this.state.page),
+      limit: Some(fetchLimit),
+      auth: auth(false).ok(),
+      type_: this.state.filter_action,
+      other_person_id: this.state.filter_user,
+      mod_person_id: this.state.filter_mod,
+    });
     WebSocketService.Instance.send(wsClient.getModlog(modlogForm));
 
-    if (this.state.communityId) {
-      let communityForm: GetCommunity = {
-        id: this.state.communityId,
-        name: this.state.communityName,
-      };
-      WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
+    this.state.communityId.match({
+      some: id => {
+        let communityForm = new GetCommunity({
+          id: Some(id),
+          name: None,
+          auth: auth(false).ok(),
+        });
+        WebSocketService.Instance.send(wsClient.getCommunity(communityForm));
+      },
+      none: void 0,
+    });
+  }
+
+  setupUserFilter() {
+    if (isBrowser()) {
+      let selectId: any = document.getElementById("filter-user");
+      if (selectId) {
+        this.userChoices = new Choices(selectId, choicesModLogConfig);
+        this.userChoices.passedElement.element.addEventListener(
+          "choice",
+          (e: any) => {
+            this.state.filter_user = Some(Number(e.detail.choice.value));
+            this.setState(this.state);
+            this.refetch();
+          },
+          false
+        );
+        this.userChoices.passedElement.element.addEventListener(
+          "search",
+          debounce(async (e: any) => {
+            try {
+              let users = (await fetchUsers(e.detail.value)).users;
+              this.userChoices.setChoices(
+                users.map(u => {
+                  return {
+                    value: u.person.id.toString(),
+                    label: u.person.name,
+                  };
+                }),
+                "value",
+                "label",
+                true
+              );
+            } catch (err) {
+              console.log(err);
+            }
+          }),
+          false
+        );
+      }
+    }
+  }
+
+  setupModFilter() {
+    if (isBrowser()) {
+      let selectId: any = document.getElementById("filter-mod");
+      if (selectId) {
+        this.modChoices = new Choices(selectId, choicesModLogConfig);
+        this.modChoices.passedElement.element.addEventListener(
+          "choice",
+          (e: any) => {
+            this.state.filter_mod = Some(Number(e.detail.choice.value));
+            this.setState(this.state);
+            this.refetch();
+          },
+          false
+        );
+        this.modChoices.passedElement.element.addEventListener(
+          "search",
+          debounce(async (e: any) => {
+            try {
+              let mods = (await fetchUsers(e.detail.value)).users;
+              this.modChoices.setChoices(
+                mods.map(u => {
+                  return {
+                    value: u.person.id.toString(),
+                    label: u.person.name,
+                  };
+                }),
+                "value",
+                "label",
+                true
+              );
+            } catch (err) {
+              console.log(err);
+            }
+          }),
+          false
+        );
+      }
     }
   }
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
     let pathSplit = req.path.split("/");
-    let communityId = pathSplit[3];
+    let communityId = Some(pathSplit[3]).map(Number);
     let promises: Promise<any>[] = [];
 
-    let modlogForm: GetModlog = {
-      page: 1,
-      limit: fetchLimit,
-    };
-
-    if (communityId) {
-      modlogForm.community_id = Number(communityId);
-    }
+    let modlogForm = new GetModlog({
+      page: Some(1),
+      limit: Some(fetchLimit),
+      community_id: communityId,
+      mod_person_id: None,
+      auth: req.auth,
+      type_: ModlogActionType.All,
+      other_person_id: None,
+    });
 
     promises.push(req.client.getModlog(modlogForm));
 
-    if (communityId) {
-      let communityForm: GetCommunity = {
-        id: Number(communityId),
-      };
+    if (communityId.isSome()) {
+      let communityForm = new GetCommunity({
+        id: communityId,
+        name: None,
+        auth: req.auth,
+      });
       promises.push(req.client.getCommunity(communityForm));
+    } else {
+      promises.push(Promise.resolve());
     }
     return promises;
   }
@@ -526,14 +828,15 @@ export class Modlog extends Component<any, ModlogState> {
       toast(i18n.t(msg.error), "danger");
       return;
     } else if (op == UserOperation.GetModlog) {
-      let data = wsJsonToRes<GetModlogResponse>(msg).data;
+      let data = wsJsonToRes<GetModlogResponse>(msg, GetModlogResponse);
       this.state.loading = false;
       window.scrollTo(0, 0);
-      this.state.res = data;
+      this.state.res = Some(data);
       this.setState(this.state);
     } else if (op == UserOperation.GetCommunity) {
-      let data = wsJsonToRes<GetCommunityResponse>(msg).data;
-      this.state.communityMods = data.moderators;
+      let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
+      this.state.communityMods = Some(data.moderators);
+      this.state.communityName = Some(data.community_view.community.name);
     }
   }
 }
index c18dafaa4b551237f7c21494ff6c40238117e3d2..2a8a7b2984640cade3ebe22dc365fface8dc794f 100644 (file)
@@ -1,48 +1,55 @@
+import { None, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import {
   BlockPersonResponse,
+  CommentReplyResponse,
+  CommentReplyView,
+  CommentReportResponse,
   CommentResponse,
+  CommentSortType,
   CommentView,
   GetPersonMentions,
   GetPersonMentionsResponse,
   GetPrivateMessages,
   GetReplies,
   GetRepliesResponse,
+  GetSiteResponse,
   PersonMentionResponse,
   PersonMentionView,
+  PostReportResponse,
   PrivateMessageResponse,
   PrivateMessagesResponse,
   PrivateMessageView,
-  SiteView,
-  SortType,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
-import { InitialFetchRequest } from "../../interfaces";
+import { CommentViewType, InitialFetchRequest } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   commentsToFlatNodes,
   createCommentLikeRes,
   editCommentRes,
+  enableDownvotes,
   fetchLimit,
   isBrowser,
+  relTags,
   saveCommentRes,
   setIsoData,
   setupTippy,
   toast,
   updatePersonBlock,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { CommentNodes } from "../comment/comment-nodes";
+import { CommentSortSelect } from "../common/comment-sort-select";
 import { HtmlTags } from "../common/html-tags";
 import { Icon, Spinner } from "../common/icon";
 import { Paginator } from "../common/paginator";
-import { SortSelect } from "../common/sort-select";
 import { PrivateMessage } from "../private_message/private-message";
 
 enum UnreadOrAll {
@@ -65,25 +72,30 @@ enum ReplyEnum {
 type ReplyType = {
   id: number;
   type_: ReplyEnum;
-  view: CommentView | PrivateMessageView | PersonMentionView;
+  view: CommentView | PrivateMessageView | PersonMentionView | CommentReplyView;
   published: string;
 };
 
 interface InboxState {
   unreadOrAll: UnreadOrAll;
   messageType: MessageType;
-  replies: CommentView[];
+  replies: CommentReplyView[];
   mentions: PersonMentionView[];
   messages: PrivateMessageView[];
   combined: ReplyType[];
-  sort: SortType;
+  sort: CommentSortType;
   page: number;
-  site_view: SiteView;
+  siteRes: GetSiteResponse;
   loading: boolean;
 }
 
 export class Inbox extends Component<any, InboxState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(
+    this.context,
+    GetRepliesResponse,
+    GetPersonMentionsResponse,
+    PrivateMessagesResponse
+  );
   private subscription: Subscription;
   private emptyState: InboxState = {
     unreadOrAll: UnreadOrAll.Unread,
@@ -92,9 +104,9 @@ export class Inbox extends Component<any, InboxState> {
     mentions: [],
     messages: [],
     combined: [],
-    sort: SortType.New,
+    sort: CommentSortType.New,
     page: 1,
-    site_view: this.isoData.site_res.site_view,
+    siteRes: this.isoData.site_res,
     loading: true,
   };
 
@@ -105,7 +117,7 @@ export class Inbox extends Component<any, InboxState> {
     this.handleSortChange = this.handleSortChange.bind(this);
     this.handlePageChange = this.handlePageChange.bind(this);
 
-    if (!UserService.Instance.myUserInfo && isBrowser()) {
+    if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
       toast(i18n.t("not_logged_in"), "danger");
       this.context.router.history.push(`/login`);
     }
@@ -115,9 +127,13 @@ export class Inbox extends Component<any, InboxState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.replies = this.isoData.routeData[0].replies || [];
-      this.state.mentions = this.isoData.routeData[1].mentions || [];
-      this.state.messages = this.isoData.routeData[2].messages || [];
+      this.state.replies =
+        (this.isoData.routeData[0] as GetRepliesResponse).replies || [];
+      this.state.mentions =
+        (this.isoData.routeData[1] as GetPersonMentionsResponse).mentions || [];
+      this.state.messages =
+        (this.isoData.routeData[2] as PrivateMessagesResponse)
+          .private_messages || [];
       this.state.combined = this.buildCombined();
       this.state.loading = false;
     } else {
@@ -132,12 +148,23 @@ export class Inbox extends Component<any, InboxState> {
   }
 
   get documentTitle(): string {
-    return `@${
-      UserService.Instance.myUserInfo.local_user_view.person.name
-    } ${i18n.t("inbox")} - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView =>
+        UserService.Instance.myUserInfo.match({
+          some: mui =>
+            `@${mui.local_user_view.person.name} ${i18n.t("inbox")} - ${
+              siteView.site.name
+            }`,
+          none: "",
+        }),
+      none: "",
+    });
   }
 
   render() {
+    let inboxRss = auth()
+      .ok()
+      .map(a => `/feeds/inbox/${a}.xml`);
     return (
       <div class="container">
         {this.state.loading ? (
@@ -150,18 +177,26 @@ export class Inbox extends Component<any, InboxState> {
               <HtmlTags
                 title={this.documentTitle}
                 path={this.context.router.route.match.url}
+                description={None}
+                image={None}
               />
               <h5 class="mb-2">
                 {i18n.t("inbox")}
-                <small>
-                  <a
-                    href={`/feeds/inbox/${UserService.Instance.auth}.xml`}
-                    title="RSS"
-                    rel="noopener"
-                  >
-                    <Icon icon="rss" classes="ml-2 text-muted small" />
-                  </a>
-                </small>
+                {inboxRss.match({
+                  some: rss => (
+                    <small>
+                      <a href={rss} title="RSS" rel={relTags}>
+                        <Icon icon="rss" classes="ml-2 text-muted small" />
+                      </a>
+                      <link
+                        rel="alternate"
+                        type="application/atom+xml"
+                        href={rss}
+                      />
+                    </small>
+                  ),
+                  none: <></>,
+                })}
               </h5>
               {this.state.replies.length +
                 this.state.mentions.length +
@@ -290,19 +325,17 @@ export class Inbox extends Component<any, InboxState> {
       <div className="mb-2">
         <span class="mr-3">{this.unreadOrAllRadios()}</span>
         <span class="mr-3">{this.messageTypeRadios()}</span>
-        <SortSelect
+        <CommentSortSelect
           sort={this.state.sort}
           onChange={this.handleSortChange}
-          hideHot
-          hideMostComments
         />
       </div>
     );
   }
 
-  replyToReplyType(r: CommentView): ReplyType {
+  replyToReplyType(r: CommentReplyView): ReplyType {
     return {
-      id: r.comment.id,
+      id: r.comment_reply.id,
       type_: ReplyEnum.Reply,
       view: r,
       published: r.comment.published,
@@ -349,24 +382,40 @@ export class Inbox extends Component<any, InboxState> {
         return (
           <CommentNodes
             key={i.id}
-            nodes={[{ comment_view: i.view as CommentView }]}
+            nodes={[
+              { comment_view: i.view as CommentView, children: [], depth: 0 },
+            ]}
+            viewType={CommentViewType.Flat}
+            moderators={None}
+            admins={None}
+            maxCommentsShown={None}
             noIndent
             markable
             showCommunity
             showContext
-            enableDownvotes={this.state.site_view.site.enable_downvotes}
+            enableDownvotes={enableDownvotes(this.state.siteRes)}
           />
         );
       case ReplyEnum.Mention:
         return (
           <CommentNodes
             key={i.id}
-            nodes={[{ comment_view: i.view as PersonMentionView }]}
+            nodes={[
+              {
+                comment_view: i.view as PersonMentionView,
+                children: [],
+                depth: 0,
+              },
+            ]}
+            viewType={CommentViewType.Flat}
+            moderators={None}
+            admins={None}
+            maxCommentsShown={None}
             noIndent
             markable
             showCommunity
             showContext
-            enableDownvotes={this.state.site_view.site.enable_downvotes}
+            enableDownvotes={enableDownvotes(this.state.siteRes)}
           />
         );
       case ReplyEnum.Message:
@@ -390,11 +439,15 @@ export class Inbox extends Component<any, InboxState> {
       <div>
         <CommentNodes
           nodes={commentsToFlatNodes(this.state.replies)}
+          viewType={CommentViewType.Flat}
+          moderators={None}
+          admins={None}
+          maxCommentsShown={None}
           noIndent
           markable
           showCommunity
           showContext
-          enableDownvotes={this.state.site_view.site.enable_downvotes}
+          enableDownvotes={enableDownvotes(this.state.siteRes)}
         />
       </div>
     );
@@ -406,12 +459,16 @@ export class Inbox extends Component<any, InboxState> {
         {this.state.mentions.map(umv => (
           <CommentNodes
             key={umv.person_mention.id}
-            nodes={[{ comment_view: umv }]}
+            nodes={[{ comment_view: umv, children: [], depth: 0 }]}
+            viewType={CommentViewType.Flat}
+            moderators={None}
+            admins={None}
+            maxCommentsShown={None}
             noIndent
             markable
             showCommunity
             showContext
-            enableDownvotes={this.state.site_view.site.enable_downvotes}
+            enableDownvotes={enableDownvotes(this.state.siteRes)}
           />
         ))}
       </div>
@@ -453,69 +510,76 @@ export class Inbox extends Component<any, InboxState> {
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
     let promises: Promise<any>[] = [];
 
+    let sort = Some(CommentSortType.New);
+
     // It can be /u/me, or /username/1
-    let repliesForm: GetReplies = {
-      sort: SortType.New,
-      unread_only: true,
-      page: 1,
-      limit: fetchLimit,
-      auth: req.auth,
-    };
+    let repliesForm = new GetReplies({
+      sort,
+      unread_only: Some(true),
+      page: Some(1),
+      limit: Some(fetchLimit),
+      auth: req.auth.unwrap(),
+    });
     promises.push(req.client.getReplies(repliesForm));
 
-    let personMentionsForm: GetPersonMentions = {
-      sort: SortType.New,
-      unread_only: true,
-      page: 1,
-      limit: fetchLimit,
-      auth: req.auth,
-    };
+    let personMentionsForm = new GetPersonMentions({
+      sort,
+      unread_only: Some(true),
+      page: Some(1),
+      limit: Some(fetchLimit),
+      auth: req.auth.unwrap(),
+    });
     promises.push(req.client.getPersonMentions(personMentionsForm));
 
-    let privateMessagesForm: GetPrivateMessages = {
-      unread_only: true,
-      page: 1,
-      limit: fetchLimit,
-      auth: req.auth,
-    };
+    let privateMessagesForm = new GetPrivateMessages({
+      unread_only: Some(true),
+      page: Some(1),
+      limit: Some(fetchLimit),
+      auth: req.auth.unwrap(),
+    });
     promises.push(req.client.getPrivateMessages(privateMessagesForm));
 
     return promises;
   }
 
   refetch() {
-    let repliesForm: GetReplies = {
-      sort: this.state.sort,
-      unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
-      page: this.state.page,
-      limit: fetchLimit,
-      auth: authField(),
-    };
+    let sort = Some(this.state.sort);
+    let unread_only = Some(this.state.unreadOrAll == UnreadOrAll.Unread);
+    let page = Some(this.state.page);
+    let limit = Some(fetchLimit);
+
+    let repliesForm = new GetReplies({
+      sort,
+      unread_only,
+      page,
+      limit,
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.getReplies(repliesForm));
 
-    let personMentionsForm: GetPersonMentions = {
-      sort: this.state.sort,
-      unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
-      page: this.state.page,
-      limit: fetchLimit,
-      auth: authField(),
-    };
+    let personMentionsForm = new GetPersonMentions({
+      sort,
+      unread_only,
+      page,
+      limit,
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(
       wsClient.getPersonMentions(personMentionsForm)
     );
 
-    let privateMessagesForm: GetPrivateMessages = {
-      unread_only: this.state.unreadOrAll == UnreadOrAll.Unread,
-      page: this.state.page,
-      limit: fetchLimit,
-      auth: authField(),
-    };
+    let privateMessagesForm = new GetPrivateMessages({
+      unread_only,
+      page,
+      limit,
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(
       wsClient.getPrivateMessages(privateMessagesForm)
     );
   }
 
-  handleSortChange(val: SortType) {
+  handleSortChange(val: CommentSortType) {
     this.state.sort = val;
     this.state.page = 1;
     this.setState(this.state);
@@ -525,17 +589,27 @@ export class Inbox extends Component<any, InboxState> {
   markAllAsRead(i: Inbox) {
     WebSocketService.Instance.send(
       wsClient.markAllAsRead({
-        auth: authField(),
+        auth: auth().unwrap(),
       })
     );
     i.state.replies = [];
     i.state.mentions = [];
     i.state.messages = [];
-    i.sendUnreadCount();
+    i.state.combined = i.buildCombined();
+    UserService.Instance.unreadInboxCountSub.next(0);
     window.scrollTo(0, 0);
     i.setState(i.state);
   }
 
+  sendUnreadCount(read: boolean) {
+    let urcs = UserService.Instance.unreadInboxCountSub;
+    if (read) {
+      urcs.next(urcs.getValue() - 1);
+    } else {
+      urcs.next(urcs.getValue() + 1);
+    }
+  }
+
   parseMessage(msg: any) {
     let op = wsUserOp(msg);
     console.log(msg);
@@ -545,32 +619,38 @@ export class Inbox extends Component<any, InboxState> {
     } else if (msg.reconnect) {
       this.refetch();
     } else if (op == UserOperation.GetReplies) {
-      let data = wsJsonToRes<GetRepliesResponse>(msg).data;
+      let data = wsJsonToRes<GetRepliesResponse>(msg, GetRepliesResponse);
       this.state.replies = data.replies;
       this.state.combined = this.buildCombined();
       this.state.loading = false;
-      this.sendUnreadCount();
       window.scrollTo(0, 0);
       this.setState(this.state);
       setupTippy();
     } else if (op == UserOperation.GetPersonMentions) {
-      let data = wsJsonToRes<GetPersonMentionsResponse>(msg).data;
+      let data = wsJsonToRes<GetPersonMentionsResponse>(
+        msg,
+        GetPersonMentionsResponse
+      );
       this.state.mentions = data.mentions;
       this.state.combined = this.buildCombined();
-      this.sendUnreadCount();
       window.scrollTo(0, 0);
       this.setState(this.state);
       setupTippy();
     } else if (op == UserOperation.GetPrivateMessages) {
-      let data = wsJsonToRes<PrivateMessagesResponse>(msg).data;
+      let data = wsJsonToRes<PrivateMessagesResponse>(
+        msg,
+        PrivateMessagesResponse
+      );
       this.state.messages = data.private_messages;
       this.state.combined = this.buildCombined();
-      this.sendUnreadCount();
       window.scrollTo(0, 0);
       this.setState(this.state);
       setupTippy();
     } else if (op == UserOperation.EditPrivateMessage) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
       let found: PrivateMessageView = this.state.messages.find(
         m =>
           m.private_message.id === data.private_message_view.private_message.id
@@ -586,7 +666,10 @@ export class Inbox extends Component<any, InboxState> {
       }
       this.setState(this.state);
     } else if (op == UserOperation.DeletePrivateMessage) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
       let found: PrivateMessageView = this.state.messages.find(
         m =>
           m.private_message.id === data.private_message_view.private_message.id
@@ -602,7 +685,10 @@ export class Inbox extends Component<any, InboxState> {
       }
       this.setState(this.state);
     } else if (op == UserOperation.MarkPrivateMessageAsRead) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
       let found: PrivateMessageView = this.state.messages.find(
         m =>
           m.private_message.id === data.private_message_view.private_message.id
@@ -633,7 +719,7 @@ export class Inbox extends Component<any, InboxState> {
             data.private_message_view.private_message.read;
         }
       }
-      this.sendUnreadCount();
+      this.sendUnreadCount(data.private_message_view.private_message.read);
       this.setState(this.state);
     } else if (op == UserOperation.MarkAllAsRead) {
       // Moved to be instant
@@ -642,38 +728,56 @@ export class Inbox extends Component<any, InboxState> {
       op == UserOperation.DeleteComment ||
       op == UserOperation.RemoveComment
     ) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       editCommentRes(data.comment_view, this.state.replies);
       this.setState(this.state);
-    } else if (op == UserOperation.MarkCommentAsRead) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-
-      // If youre in the unread view, just remove it from the list
-      if (
-        this.state.unreadOrAll == UnreadOrAll.Unread &&
-        data.comment_view.comment.read
-      ) {
-        this.state.replies = this.state.replies.filter(
-          r => r.comment.id !== data.comment_view.comment.id
-        );
-        this.state.combined = this.state.combined.filter(
-          r => r.id !== data.comment_view.comment.id
-        );
-      } else {
-        let found = this.state.replies.find(
-          c => c.comment.id == data.comment_view.comment.id
-        );
+    } else if (op == UserOperation.MarkCommentReplyAsRead) {
+      let data = wsJsonToRes<CommentReplyResponse>(msg, CommentReplyResponse);
+      console.log(data);
+
+      let found = this.state.replies.find(
+        c => c.comment_reply.id == data.comment_reply_view.comment_reply.id
+      );
+
+      if (found) {
         let combinedView = this.state.combined.find(
-          i => i.id == data.comment_view.comment.id
-        ).view as CommentView;
-        found.comment.read = combinedView.comment.read =
-          data.comment_view.comment.read;
+          i => i.id == data.comment_reply_view.comment_reply.id
+        ).view as CommentReplyView;
+        found.comment.content = combinedView.comment.content =
+          data.comment_reply_view.comment.content;
+        found.comment.updated = combinedView.comment.updated =
+          data.comment_reply_view.comment.updated;
+        found.comment.removed = combinedView.comment.removed =
+          data.comment_reply_view.comment.removed;
+        found.comment.deleted = combinedView.comment.deleted =
+          data.comment_reply_view.comment.deleted;
+        found.counts.upvotes = combinedView.counts.upvotes =
+          data.comment_reply_view.counts.upvotes;
+        found.counts.downvotes = combinedView.counts.downvotes =
+          data.comment_reply_view.counts.downvotes;
+        found.counts.score = combinedView.counts.score =
+          data.comment_reply_view.counts.score;
+
+        // If youre in the unread view, just remove it from the list
+        if (
+          this.state.unreadOrAll == UnreadOrAll.Unread &&
+          data.comment_reply_view.comment_reply.read
+        ) {
+          this.state.replies = this.state.replies.filter(
+            r => r.comment_reply.id !== data.comment_reply_view.comment_reply.id
+          );
+          this.state.combined = this.state.combined.filter(
+            r => r.id !== data.comment_reply_view.comment_reply.id
+          );
+        } else {
+          found.comment_reply.read = combinedView.comment_reply.read =
+            data.comment_reply_view.comment_reply.read;
+        }
       }
-      this.sendUnreadCount();
+      this.sendUnreadCount(data.comment_reply_view.comment_reply.read);
       this.setState(this.state);
-      setupTippy();
     } else if (op == UserOperation.MarkPersonMentionAsRead) {
-      let data = wsJsonToRes<PersonMentionResponse>(msg).data;
+      let data = wsJsonToRes<PersonMentionResponse>(msg, PersonMentionResponse);
 
       // TODO this might not be correct, it might need to use the comment id
       let found = this.state.mentions.find(
@@ -717,69 +821,58 @@ export class Inbox extends Component<any, InboxState> {
             data.person_mention_view.person_mention.read;
         }
       }
-      this.sendUnreadCount();
+      this.sendUnreadCount(data.person_mention_view.person_mention.read);
       this.setState(this.state);
-    } else if (op == UserOperation.CreateComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-
-      if (
-        data.recipient_ids.includes(
-          UserService.Instance.myUserInfo.local_user_view.local_user.id
-        )
-      ) {
-        this.state.replies.unshift(data.comment_view);
-        this.state.combined.unshift(this.replyToReplyType(data.comment_view));
-        this.setState(this.state);
-      } else if (
-        data.comment_view.creator.id ==
-        UserService.Instance.myUserInfo.local_user_view.person.id
-      ) {
-        // TODO this seems wrong, you should be using form_id
-        toast(i18n.t("reply_sent"));
-      }
     } else if (op == UserOperation.CreatePrivateMessage) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
-      if (
-        data.private_message_view.recipient.id ==
-        UserService.Instance.myUserInfo.local_user_view.person.id
-      ) {
-        this.state.messages.unshift(data.private_message_view);
-        this.state.combined.unshift(
-          this.messageToReplyType(data.private_message_view)
-        );
-        this.setState(this.state);
-      }
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          if (
+            data.private_message_view.recipient.id ==
+            mui.local_user_view.person.id
+          ) {
+            this.state.messages.unshift(data.private_message_view);
+            this.state.combined.unshift(
+              this.messageToReplyType(data.private_message_view)
+            );
+            this.setState(this.state);
+          }
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.SaveComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       saveCommentRes(data.comment_view, this.state.replies);
       this.setState(this.state);
       setupTippy();
     } else if (op == UserOperation.CreateCommentLike) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       createCommentLikeRes(data.comment_view, this.state.replies);
       this.setState(this.state);
     } else if (op == UserOperation.BlockPerson) {
-      let data = wsJsonToRes<BlockPersonResponse>(msg).data;
+      let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
       updatePersonBlock(data);
+    } else if (op == UserOperation.CreatePostReport) {
+      let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (op == UserOperation.CreateCommentReport) {
+      let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
     }
   }
 
-  sendUnreadCount() {
-    UserService.Instance.unreadCountSub.next(this.unreadCount());
+  isMention(view: any): view is PersonMentionView {
+    return (view as PersonMentionView).person_mention !== undefined;
   }
 
-  unreadCount(): number {
-    return (
-      this.state.replies.filter(r => !r.comment.read).length +
-      this.state.mentions.filter(r => !r.person_mention.read).length +
-      this.state.messages.filter(
-        r =>
-          UserService.Instance.myUserInfo &&
-          !r.private_message.read &&
-          // TODO also seems very strange and wrong
-          r.creator.id !==
-            UserService.Instance.myUserInfo.local_user_view.person.id
-      ).length
-    );
+  isReply(view: any): view is CommentReplyView {
+    return (view as CommentReplyView).comment_reply !== undefined;
   }
 }
similarity index 90%
rename from src/shared/components/home/password_change.tsx
rename to src/shared/components/person/password-change.tsx
index 2b23ddcb9282550d266869cf533cbc6798c00eae..8120fe97630e67d60a972b9103fdeb4d5071a7e7 100644 (file)
@@ -1,9 +1,12 @@
+import { None } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import {
+  GetSiteResponse,
   LoginResponse,
   PasswordChange as PasswordChangeForm,
-  SiteView,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
@@ -14,9 +17,7 @@ import {
   setIsoData,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
@@ -24,7 +25,7 @@ import { Spinner } from "../common/icon";
 interface State {
   passwordChangeForm: PasswordChangeForm;
   loading: boolean;
-  site_view: SiteView;
+  siteRes: GetSiteResponse;
 }
 
 export class PasswordChange extends Component<any, State> {
@@ -32,13 +33,13 @@ export class PasswordChange extends Component<any, State> {
   private subscription: Subscription;
 
   emptyState: State = {
-    passwordChangeForm: {
+    passwordChangeForm: new PasswordChangeForm({
       token: this.props.match.params.token,
       password: undefined,
       password_verify: undefined,
-    },
+    }),
     loading: false,
-    site_view: this.isoData.site_res.site_view,
+    siteRes: this.isoData.site_res,
   };
 
   constructor(props: any, context: any) {
@@ -57,7 +58,10 @@ export class PasswordChange extends Component<any, State> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("password_change")} - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("password_change")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
@@ -66,6 +70,8 @@ export class PasswordChange extends Component<any, State> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         <div class="row">
           <div class="col-12 col-lg-6 offset-lg-3 mb-4">
@@ -156,7 +162,7 @@ export class PasswordChange extends Component<any, State> {
       this.setState(this.state);
       return;
     } else if (op == UserOperation.PasswordChange) {
-      let data = wsJsonToRes<LoginResponse>(msg).data;
+      let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
       this.state = this.emptyState;
       this.setState(this.state);
       UserService.Instance.login(data);
index ccc055b947888b50c81d0940eca8164ee2fef6f1..6ce7a8b8d0b02c3070866adfa9983b15ed58de12 100644 (file)
@@ -1,3 +1,4 @@
+import { None, Some } from "@sniptt/monads/build";
 import { Component } from "inferno";
 import {
   CommentView,
@@ -6,7 +7,7 @@ import {
   PostView,
   SortType,
 } from "lemmy-js-client";
-import { PersonDetailsView } from "../../interfaces";
+import { CommentViewType, PersonDetailsView } from "../../interfaces";
 import { commentsToFlatNodes, setupTippy } from "../../utils";
 import { CommentNodes } from "../comment/comment-nodes";
 import { Paginator } from "../common/paginator";
@@ -42,7 +43,6 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
     this.handlePageChange = this.handlePageChange.bind(this);
   }
 
-  // TODO needed here?
   componentDidMount() {
     setupTippy();
   }
@@ -89,8 +89,11 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
         return (
           <CommentNodes
             key={i.id}
-            nodes={[{ comment_view: c }]}
-            admins={this.props.admins}
+            nodes={[{ comment_view: c, children: [], depth: 0 }]}
+            viewType={CommentViewType.Flat}
+            admins={Some(this.props.admins)}
+            moderators={None}
+            maxCommentsShown={None}
             noBorder
             noIndent
             showCommunity
@@ -105,7 +108,9 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
           <PostListing
             key={i.id}
             post_view={p}
-            admins={this.props.admins}
+            admins={Some(this.props.admins)}
+            duplicates={None}
+            moderators={None}
             showCommunity
             enableDownvotes={this.props.enableDownvotes}
             enableNsfw={this.props.enableNsfw}
@@ -155,7 +160,10 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
       <div>
         <CommentNodes
           nodes={commentsToFlatNodes(this.props.personRes.comments)}
-          admins={this.props.admins}
+          viewType={CommentViewType.Flat}
+          admins={Some(this.props.admins)}
+          moderators={None}
+          maxCommentsShown={None}
           noIndent
           showCommunity
           showContext
@@ -172,8 +180,10 @@ export class PersonDetails extends Component<PersonDetailsProps, any> {
           <>
             <PostListing
               post_view={post}
-              admins={this.props.admins}
+              admins={Some(this.props.admins)}
               showCommunity
+              duplicates={None}
+              moderators={None}
               enableDownvotes={this.props.enableDownvotes}
               enableNsfw={this.props.enableNsfw}
             />
index 60e509cc929d6c02c7736cde054e9810d189eede..88b88820252d141767be8aa3cd5353c76858ee72 100644 (file)
@@ -1,7 +1,7 @@
 import { Component } from "inferno";
 import { Link } from "inferno-router";
 import { PersonSafe } from "lemmy-js-client";
-import { hostname, isCakeDay, showAvatars } from "../../utils";
+import { hostname, isCakeDay, relTags, showAvatars } from "../../utils";
 import { PictrsImage } from "../common/pictrs-image";
 import { CakeDay } from "./cake-day";
 
@@ -21,7 +21,7 @@ export class PersonListing extends Component<PersonListingProps, any> {
 
   render() {
     let person = this.props.person;
-    let local = person.local == null ? true : person.local;
+    let local = person.local;
     let apubName: string, link: string;
 
     if (local) {
@@ -37,11 +37,9 @@ export class PersonListing extends Component<PersonListingProps, any> {
 
     let displayName = this.props.useApubName
       ? apubName
-      : person.display_name
-      ? person.display_name
-      : apubName;
+      : person.display_name.unwrapOr(apubName);
 
-    if (this.props.showApubName && !local && person.display_name) {
+    if (this.props.showApubName && !local && person.display_name.isSome()) {
       displayName = `${displayName} (${apubName})`;
     }
 
@@ -60,6 +58,7 @@ export class PersonListing extends Component<PersonListingProps, any> {
             title={apubName}
             className={this.props.muted ? "text-muted" : "text-info"}
             href={link}
+            rel={relTags}
           >
             {this.avatarAndName(displayName)}
           </a>
@@ -71,12 +70,14 @@ export class PersonListing extends Component<PersonListingProps, any> {
   }
 
   avatarAndName(displayName: string) {
-    let person = this.props.person;
     return (
       <>
-        {!this.props.hideAvatar && person.avatar && showAvatars() && (
-          <PictrsImage src={person.avatar} icon />
-        )}
+        {this.props.person.avatar.match({
+          some: avatar =>
+            !this.props.hideAvatar &&
+            showAvatars() && <PictrsImage src={avatar} icon />,
+          none: <></>,
+        })}
         <span>{displayName}</span>
       </>
     );
index 815f2fd3791beedbe939ed3a3652e0153cf45fd1..9de6d0b967abe06c9380d90eb3f3ef81697d5b8b 100644 (file)
@@ -1,16 +1,23 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
   AddAdminResponse,
+  BanPerson,
   BanPersonResponse,
+  BlockPerson,
   BlockPersonResponse,
   CommentResponse,
   GetPersonDetails,
   GetPersonDetailsResponse,
   GetSiteResponse,
   PostResponse,
+  PurgeItemResponse,
   SortType,
+  toUndefined,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import moment from "moment";
 import { Subscription } from "rxjs";
@@ -18,28 +25,33 @@ import { i18n } from "../../i18next";
 import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
+  canMod,
+  capitalizeFirstLetter,
   createCommentLikeRes,
   createPostLikeFindRes,
   editCommentRes,
   editPostFindRes,
+  enableDownvotes,
+  enableNsfw,
   fetchLimit,
+  futureDaysToUnixTime,
   getUsernameFromProps,
+  isAdmin,
+  isBanned,
   mdToHtml,
-  previewLines,
+  numToSI,
+  relTags,
   restoreScrollPosition,
   routeSortTypeToEnum,
   saveCommentRes,
   saveScrollPosition,
   setIsoData,
-  setOptionalAuth,
   setupTippy,
   toast,
   updatePersonBlock,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { BannerIconHeader } from "../common/banner-icon-header";
 import { HtmlTags } from "../common/html-tags";
@@ -51,12 +63,17 @@ import { PersonDetails } from "./person-details";
 import { PersonListing } from "./person-listing";
 
 interface ProfileState {
-  personRes: GetPersonDetailsResponse;
+  personRes: Option<GetPersonDetailsResponse>;
   userName: string;
   view: PersonDetailsView;
   sort: SortType;
   page: number;
   loading: boolean;
+  personBlocked: boolean;
+  banReason: Option<string>;
+  banExpireDays: Option<number>;
+  showBanDialog: boolean;
+  removeData: boolean;
   siteRes: GetSiteResponse;
 }
 
@@ -75,16 +92,21 @@ interface UrlParams {
 }
 
 export class Profile extends Component<any, ProfileState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(this.context, GetPersonDetailsResponse);
   private subscription: Subscription;
   private emptyState: ProfileState = {
-    personRes: undefined,
+    personRes: None,
     userName: getUsernameFromProps(this.props),
     loading: true,
     view: Profile.getViewFromProps(this.props.match.view),
     sort: Profile.getSortTypeFromProps(this.props.match.sort),
     page: Profile.getPageFromProps(this.props.match.page),
+    personBlocked: false,
     siteRes: this.isoData.site_res,
+    showBanDialog: false,
+    banReason: null,
+    banExpireDays: null,
+    removeData: false,
   };
 
   constructor(props: any, context: any) {
@@ -92,38 +114,63 @@ export class Profile extends Component<any, ProfileState> {
 
     this.state = this.emptyState;
     this.handleSortChange = this.handleSortChange.bind(this);
+    this.handlePageChange = this.handlePageChange.bind(this);
 
     this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.personRes = this.isoData.routeData[0];
+      this.state.personRes = Some(
+        this.isoData.routeData[0] as GetPersonDetailsResponse
+      );
       this.state.loading = false;
     } else {
       this.fetchUserData();
     }
 
-    setupTippy();
+    this.setPersonBlock();
   }
 
   fetchUserData() {
-    let form: GetPersonDetails = {
-      username: this.state.userName,
-      sort: this.state.sort,
-      saved_only: this.state.view === PersonDetailsView.Saved,
-      page: this.state.page,
-      limit: fetchLimit,
-      auth: authField(false),
-    };
+    let form = new GetPersonDetails({
+      username: Some(this.state.userName),
+      person_id: None,
+      community_id: None,
+      sort: Some(this.state.sort),
+      saved_only: Some(this.state.view === PersonDetailsView.Saved),
+      page: Some(this.state.page),
+      limit: Some(fetchLimit),
+      auth: auth(false).ok(),
+    });
     WebSocketService.Instance.send(wsClient.getPersonDetails(form));
   }
 
-  get isCurrentUser() {
-    return (
-      UserService.Instance.myUserInfo?.local_user_view.person.id ==
-      this.state.personRes.person_view.person.id
-    );
+  get amCurrentUser() {
+    return UserService.Instance.myUserInfo.match({
+      some: mui =>
+        this.state.personRes.match({
+          some: res =>
+            mui.local_user_view.person.id == res.person_view.person.id,
+          none: false,
+        }),
+      none: false,
+    });
+  }
+
+  setPersonBlock() {
+    UserService.Instance.myUserInfo.match({
+      some: mui =>
+        this.state.personRes.match({
+          some: res => {
+            this.state.personBlocked = mui.person_blocks
+              .map(a => a.target.id)
+              .includes(res.person_view.person.id);
+          },
+          none: void 0,
+        }),
+      none: void 0,
+    });
   }
 
   static getViewFromProps(view: string): PersonDetailsView {
@@ -140,40 +187,27 @@ export class Profile extends Component<any, ProfileState> {
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
     let pathSplit = req.path.split("/");
-    let promises: Promise<any>[] = [];
-
-    // It can be /u/me, or /username/1
-    let idOrName = pathSplit[2];
-    let person_id: number;
-    let username: string;
-    if (isNaN(Number(idOrName))) {
-      username = idOrName;
-    } else {
-      person_id = Number(idOrName);
-    }
 
+    let username = pathSplit[2];
     let view = this.getViewFromProps(pathSplit[4]);
-    let sort = this.getSortTypeFromProps(pathSplit[6]);
-    let page = this.getPageFromProps(Number(pathSplit[8]));
+    let sort = Some(this.getSortTypeFromProps(pathSplit[6]));
+    let page = Some(this.getPageFromProps(Number(pathSplit[8])));
 
-    let form: GetPersonDetails = {
+    let form = new GetPersonDetails({
+      username: Some(username),
+      person_id: None,
+      community_id: None,
       sort,
-      saved_only: view === PersonDetailsView.Saved,
+      saved_only: Some(view === PersonDetailsView.Saved),
       page,
-      limit: fetchLimit,
-    };
-    setOptionalAuth(form, req.auth);
-    this.setIdOrName(form, person_id, username);
-    promises.push(req.client.getPersonDetails(form));
-    return promises;
+      limit: Some(fetchLimit),
+      auth: req.auth,
+    });
+    return [req.client.getPersonDetails(form)];
   }
 
-  static setIdOrName(obj: any, id: number, name_: string) {
-    if (id) {
-      obj.person_id = id;
-    } else {
-      obj.username = name_;
-    }
+  componentDidMount() {
+    setupTippy();
   }
 
   componentWillUnmount() {
@@ -203,13 +237,15 @@ export class Profile extends Component<any, ProfileState> {
   }
 
   get documentTitle(): string {
-    return `@${this.state.personRes.person_view.person.name} - ${this.state.siteRes.site_view.site.name}`;
-  }
-
-  get bioTag(): string {
-    return this.state.personRes.person_view.person.bio
-      ? previewLines(this.state.personRes.person_view.person.bio)
-      : undefined;
+    return this.state.siteRes.site_view.match({
+      some: siteView =>
+        this.state.personRes.match({
+          some: res =>
+            `@${res.person_view.person.name} - ${siteView.site.name}`,
+          none: "",
+        }),
+      none: "",
+    });
   }
 
   render() {
@@ -220,41 +256,44 @@ export class Profile extends Component<any, ProfileState> {
             <Spinner large />
           </h5>
         ) : (
-          <div class="row">
-            <div class="col-12 col-md-8">
-              <>
-                <HtmlTags
-                  title={this.documentTitle}
-                  path={this.context.router.route.match.url}
-                  description={this.bioTag}
-                  image={this.state.personRes.person_view.person.avatar}
-                />
-                {this.userInfo()}
-                <hr />
-              </>
-              {!this.state.loading && this.selects()}
-              <PersonDetails
-                personRes={this.state.personRes}
-                admins={this.state.siteRes.admins}
-                sort={this.state.sort}
-                page={this.state.page}
-                limit={fetchLimit}
-                enableDownvotes={
-                  this.state.siteRes.site_view.site.enable_downvotes
-                }
-                enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
-                view={this.state.view}
-                onPageChange={this.handlePageChange}
-              />
-            </div>
-
-            {!this.state.loading && (
-              <div class="col-12 col-md-4">
-                {this.moderates()}
-                {UserService.Instance.myUserInfo && this.follows()}
+          this.state.personRes.match({
+            some: res => (
+              <div class="row">
+                <div class="col-12 col-md-8">
+                  <>
+                    <HtmlTags
+                      title={this.documentTitle}
+                      path={this.context.router.route.match.url}
+                      description={res.person_view.person.bio}
+                      image={res.person_view.person.avatar}
+                    />
+                    {this.userInfo()}
+                    <hr />
+                  </>
+                  {!this.state.loading && this.selects()}
+                  <PersonDetails
+                    personRes={res}
+                    admins={this.state.siteRes.admins}
+                    sort={this.state.sort}
+                    page={this.state.page}
+                    limit={fetchLimit}
+                    enableDownvotes={enableDownvotes(this.state.siteRes)}
+                    enableNsfw={enableNsfw(this.state.siteRes)}
+                    view={this.state.view}
+                    onPageChange={this.handlePageChange}
+                  />
+                </div>
+
+                {!this.state.loading && (
+                  <div class="col-12 col-md-4">
+                    {this.moderates()}
+                    {this.amCurrentUser && this.follows()}
+                  </div>
+                )}
               </div>
-            )}
-          </div>
+            ),
+            none: <></>,
+          })
         )}
       </div>
     );
@@ -320,6 +359,8 @@ export class Profile extends Component<any, ProfileState> {
   }
 
   selects() {
+    let profileRss = `/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`;
+
     return (
       <div className="mb-2">
         <span class="mr-3">{this.viewRadios()}</span>
@@ -329,146 +370,339 @@ export class Profile extends Component<any, ProfileState> {
           hideHot
           hideMostComments
         />
-        <a
-          href={`/feeds/u/${this.state.userName}.xml?sort=${this.state.sort}`}
-          rel="noopener"
-          title="RSS"
-        >
+        <a href={profileRss} rel={relTags} title="RSS">
           <Icon icon="rss" classes="text-muted small mx-2" />
         </a>
+        <link rel="alternate" type="application/atom+xml" href={profileRss} />
       </div>
     );
   }
+  handleBlockPerson(personId: number) {
+    if (personId != 0) {
+      let blockUserForm = new BlockPerson({
+        person_id: personId,
+        block: true,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+    }
+  }
+  handleUnblockPerson(recipientId: number) {
+    let blockUserForm = new BlockPerson({
+      person_id: recipientId,
+      block: false,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
+  }
 
   userInfo() {
-    let pv = this.state.personRes?.person_view;
-
-    return (
-      <div>
-        <BannerIconHeader banner={pv.person.banner} icon={pv.person.avatar} />
-        <div class="mb-3">
-          <div class="">
-            <div class="mb-0 d-flex flex-wrap">
-              <div>
-                {pv.person.display_name && (
-                  <h5 class="mb-0">{pv.person.display_name}</h5>
-                )}
-                <ul class="list-inline mb-2">
-                  <li className="list-inline-item">
-                    <PersonListing
-                      person={pv.person}
-                      realLink
-                      useApubName
-                      muted
-                      hideAvatar
-                    />
-                  </li>
-                  {pv.person.banned && (
-                    <li className="list-inline-item badge badge-danger">
-                      {i18n.t("banned")}
+    return this.state.personRes
+      .map(r => r.person_view)
+      .match({
+        some: pv => (
+          <div>
+            <BannerIconHeader
+              banner={pv.person.banner}
+              icon={pv.person.avatar}
+            />
+            <div class="mb-3">
+              <div class="">
+                <div class="mb-0 d-flex flex-wrap">
+                  <div>
+                    {pv.person.display_name && (
+                      <h5 class="mb-0">{pv.person.display_name}</h5>
+                    )}
+                    <ul class="list-inline mb-2">
+                      <li className="list-inline-item">
+                        <PersonListing
+                          person={pv.person}
+                          realLink
+                          useApubName
+                          muted
+                          hideAvatar
+                        />
+                      </li>
+                      {isBanned(pv.person) && (
+                        <li className="list-inline-item badge badge-danger">
+                          {i18n.t("banned")}
+                        </li>
+                      )}
+                      {pv.person.admin && (
+                        <li className="list-inline-item badge badge-light">
+                          {i18n.t("admin")}
+                        </li>
+                      )}
+                      {pv.person.bot_account && (
+                        <li className="list-inline-item badge badge-light">
+                          {i18n.t("bot_account").toLowerCase()}
+                        </li>
+                      )}
+                    </ul>
+                  </div>
+                  {this.banDialog()}
+                  <div className="flex-grow-1 unselectable pointer mx-2"></div>
+                  {!this.amCurrentUser &&
+                    UserService.Instance.myUserInfo.isSome() && (
+                      <>
+                        <a
+                          className={`d-flex align-self-start btn btn-secondary mr-2 ${
+                            !pv.person.matrix_user_id && "invisible"
+                          }`}
+                          rel={relTags}
+                          href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
+                        >
+                          {i18n.t("send_secure_message")}
+                        </a>
+                        <Link
+                          className={
+                            "d-flex align-self-start btn btn-secondary mr-2"
+                          }
+                          to={`/create_private_message/recipient/${pv.person.id}`}
+                        >
+                          {i18n.t("send_message")}
+                        </Link>
+                        {this.state.personBlocked ? (
+                          <button
+                            className={
+                              "d-flex align-self-start btn btn-secondary mr-2"
+                            }
+                            onClick={linkEvent(
+                              pv.person.id,
+                              this.handleUnblockPerson
+                            )}
+                          >
+                            {i18n.t("unblock_user")}
+                          </button>
+                        ) : (
+                          <button
+                            className={
+                              "d-flex align-self-start btn btn-secondary mr-2"
+                            }
+                            onClick={linkEvent(
+                              pv.person.id,
+                              this.handleBlockPerson
+                            )}
+                          >
+                            {i18n.t("block_user")}
+                          </button>
+                        )}
+                      </>
+                    )}
+
+                  {canMod(
+                    None,
+                    Some(this.state.siteRes.admins),
+                    pv.person.id
+                  ) &&
+                    !isAdmin(Some(this.state.siteRes.admins), pv.person.id) &&
+                    !this.state.showBanDialog &&
+                    (!isBanned(pv.person) ? (
+                      <button
+                        className={
+                          "d-flex align-self-start btn btn-secondary mr-2"
+                        }
+                        onClick={linkEvent(this, this.handleModBanShow)}
+                        aria-label={i18n.t("ban")}
+                      >
+                        {capitalizeFirstLetter(i18n.t("ban"))}
+                      </button>
+                    ) : (
+                      <button
+                        className={
+                          "d-flex align-self-start btn btn-secondary mr-2"
+                        }
+                        onClick={linkEvent(this, this.handleModBanSubmit)}
+                        aria-label={i18n.t("unban")}
+                      >
+                        {capitalizeFirstLetter(i18n.t("unban"))}
+                      </button>
+                    ))}
+                </div>
+                {pv.person.bio.match({
+                  some: bio => (
+                    <div className="d-flex align-items-center mb-2">
+                      <div
+                        className="md-div"
+                        dangerouslySetInnerHTML={mdToHtml(bio)}
+                      />
+                    </div>
+                  ),
+                  none: <></>,
+                })}
+                <div>
+                  <ul class="list-inline mb-2">
+                    <li className="list-inline-item badge badge-light">
+                      {i18n.t("number_of_posts", {
+                        count: pv.counts.post_count,
+                        formattedCount: numToSI(pv.counts.post_count),
+                      })}
                     </li>
-                  )}
-                </ul>
+                    <li className="list-inline-item badge badge-light">
+                      {i18n.t("number_of_comments", {
+                        count: pv.counts.comment_count,
+                        formattedCount: numToSI(pv.counts.comment_count),
+                      })}
+                    </li>
+                  </ul>
+                </div>
+                <div class="text-muted">
+                  {i18n.t("joined")}{" "}
+                  <MomentTime
+                    published={pv.person.published}
+                    updated={None}
+                    showAgo
+                    ignoreUpdated
+                  />
+                </div>
+                <div className="d-flex align-items-center text-muted mb-2">
+                  <Icon icon="cake" />
+                  <span className="ml-2">
+                    {i18n.t("cake_day_title")}{" "}
+                    {moment
+                      .utc(pv.person.published)
+                      .local()
+                      .format("MMM DD, YYYY")}
+                  </span>
+                </div>
               </div>
-              <div className="flex-grow-1 unselectable pointer mx-2"></div>
-              {!this.isCurrentUser && (
-                <>
-                  <a
-                    className={`d-flex align-self-start btn btn-secondary mr-2 ${
-                      !pv.person.matrix_user_id && "invisible"
-                    }`}
-                    rel="noopener"
-                    href={`https://matrix.to/#/${pv.person.matrix_user_id}`}
+            </div>
+          </div>
+        ),
+        none: <></>,
+      });
+  }
+
+  banDialog() {
+    return this.state.personRes
+      .map(r => r.person_view)
+      .match({
+        some: pv => (
+          <>
+            {this.state.showBanDialog && (
+              <form onSubmit={linkEvent(this, this.handleModBanSubmit)}>
+                <div class="form-group row col-12">
+                  <label class="col-form-label" htmlFor="profile-ban-reason">
+                    {i18n.t("reason")}
+                  </label>
+                  <input
+                    type="text"
+                    id="profile-ban-reason"
+                    class="form-control mr-2"
+                    placeholder={i18n.t("reason")}
+                    value={toUndefined(this.state.banReason)}
+                    onInput={linkEvent(this, this.handleModBanReasonChange)}
+                  />
+                  <label class="col-form-label" htmlFor={`mod-ban-expires`}>
+                    {i18n.t("expires")}
+                  </label>
+                  <input
+                    type="number"
+                    id={`mod-ban-expires`}
+                    class="form-control mr-2"
+                    placeholder={i18n.t("number_of_days")}
+                    value={toUndefined(this.state.banExpireDays)}
+                    onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
+                  />
+                  <div class="form-group">
+                    <div class="form-check">
+                      <input
+                        class="form-check-input"
+                        id="mod-ban-remove-data"
+                        type="checkbox"
+                        checked={this.state.removeData}
+                        onChange={linkEvent(
+                          this,
+                          this.handleModRemoveDataChange
+                        )}
+                      />
+                      <label
+                        class="form-check-label"
+                        htmlFor="mod-ban-remove-data"
+                        title={i18n.t("remove_content_more")}
+                      >
+                        {i18n.t("remove_content")}
+                      </label>
+                    </div>
+                  </div>
+                </div>
+                {/* TODO hold off on expires until later */}
+                {/* <div class="form-group row"> */}
+                {/*   <label class="col-form-label">Expires</label> */}
+                {/*   <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.banExpires} onInput={linkEvent(this, this.handleModBanExpiresChange)} /> */}
+                {/* </div> */}
+                <div class="form-group row">
+                  <button
+                    type="cancel"
+                    class="btn btn-secondary mr-2"
+                    aria-label={i18n.t("cancel")}
+                    onClick={linkEvent(this, this.handleModBanSubmitCancel)}
                   >
-                    {i18n.t("send_secure_message")}
-                  </a>
-                  <Link
-                    className={"d-flex align-self-start btn btn-secondary"}
-                    to={`/create_private_message/recipient/${pv.person.id}`}
+                    {i18n.t("cancel")}
+                  </button>
+                  <button
+                    type="submit"
+                    class="btn btn-secondary"
+                    aria-label={i18n.t("ban")}
                   >
-                    {i18n.t("send_message")}
-                  </Link>
-                </>
-              )}
-            </div>
-            {pv.person.bio && (
-              <div className="d-flex align-items-center mb-2">
-                <div
-                  className="md-div"
-                  dangerouslySetInnerHTML={mdToHtml(pv.person.bio)}
-                />
-              </div>
+                    {i18n.t("ban")} {pv.person.name}
+                  </button>
+                </div>
+              </form>
             )}
-            <div>
-              <ul class="list-inline mb-2">
-                <li className="list-inline-item badge badge-light">
-                  {i18n.t("number_of_posts", { count: pv.counts.post_count })}
-                </li>
-                <li className="list-inline-item badge badge-light">
-                  {i18n.t("number_of_comments", {
-                    count: pv.counts.comment_count,
-                  })}
-                </li>
-              </ul>
-            </div>
-            <div class="text-muted">
-              {i18n.t("joined")}{" "}
-              <MomentTime data={pv.person} showAgo ignoreUpdated />
-            </div>
-            <div className="d-flex align-items-center text-muted mb-2">
-              <Icon icon="cake" />
-              <span className="ml-2">
-                {i18n.t("cake_day_title")}{" "}
-                {moment.utc(pv.person.published).local().format("MMM DD, YYYY")}
-              </span>
-            </div>
-          </div>
-        </div>
-      </div>
-    );
+          </>
+        ),
+        none: <></>,
+      });
   }
 
+  // TODO test this, make sure its good
   moderates() {
-    return (
-      <div>
-        {this.state.personRes.moderates.length > 0 && (
-          <div class="card border-secondary mb-3">
-            <div class="card-body">
-              <h5>{i18n.t("moderates")}</h5>
-              <ul class="list-unstyled mb-0">
-                {this.state.personRes.moderates.map(cmv => (
-                  <li>
-                    <CommunityLink community={cmv.community} />
-                  </li>
-                ))}
-              </ul>
-            </div>
-          </div>
-        )}
-      </div>
-    );
+    return this.state.personRes
+      .map(r => r.moderates)
+      .match({
+        some: moderates => {
+          if (moderates.length > 0) {
+            <div class="card border-secondary mb-3">
+              <div class="card-body">
+                <h5>{i18n.t("moderates")}</h5>
+                <ul class="list-unstyled mb-0">
+                  {moderates.map(cmv => (
+                    <li>
+                      <CommunityLink community={cmv.community} />
+                    </li>
+                  ))}
+                </ul>
+              </div>
+            </div>;
+          }
+        },
+        none: void 0,
+      });
   }
 
   follows() {
-    let follows = UserService.Instance.myUserInfo.follows;
-    return (
-      <div>
-        {follows.length > 0 && (
-          <div class="card border-secondary mb-3">
-            <div class="card-body">
-              <h5>{i18n.t("subscribed")}</h5>
-              <ul class="list-unstyled mb-0">
-                {follows.map(cfv => (
-                  <li>
-                    <CommunityLink community={cfv.community} />
-                  </li>
-                ))}
-              </ul>
-            </div>
-          </div>
-        )}
-      </div>
-    );
+    return UserService.Instance.myUserInfo
+      .map(m => m.follows)
+      .match({
+        some: follows => {
+          if (follows.length > 0) {
+            <div class="card border-secondary mb-3">
+              <div class="card-body">
+                <h5>{i18n.t("subscribed")}</h5>
+                <ul class="list-unstyled mb-0">
+                  {follows.map(cfv => (
+                    <li>
+                      <CommunityLink community={cfv.community} />
+                    </li>
+                  ))}
+                </ul>
+              </div>
+            </div>;
+          }
+        },
+        none: void 0,
+      });
   }
 
   updateUrl(paramUpdates: UrlParams) {
@@ -487,7 +721,7 @@ export class Profile extends Component<any, ProfileState> {
   }
 
   handlePageChange(page: number) {
-    this.updateUrl({ page });
+    this.updateUrl({ page: page });
   }
 
   handleSortChange(val: SortType) {
@@ -501,6 +735,61 @@ export class Profile extends Component<any, ProfileState> {
     });
   }
 
+  handleModBanShow(i: Profile) {
+    i.state.showBanDialog = true;
+    i.setState(i.state);
+  }
+
+  handleModBanReasonChange(i: Profile, event: any) {
+    i.state.banReason = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleModBanExpireDaysChange(i: Profile, event: any) {
+    i.state.banExpireDays = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleModRemoveDataChange(i: Profile, event: any) {
+    i.state.removeData = event.target.checked;
+    i.setState(i.state);
+  }
+
+  handleModBanSubmitCancel(i: Profile, event?: any) {
+    event.preventDefault();
+    i.state.showBanDialog = false;
+    i.setState(i.state);
+  }
+
+  handleModBanSubmit(i: Profile, event?: any) {
+    if (event) event.preventDefault();
+
+    i.state.personRes
+      .map(r => r.person_view.person)
+      .match({
+        some: person => {
+          // If its an unban, restore all their data
+          let ban = !person.banned;
+          if (ban == false) {
+            i.state.removeData = false;
+          }
+          let form = new BanPerson({
+            person_id: person.id,
+            ban,
+            remove_data: Some(i.state.removeData),
+            reason: i.state.banReason,
+            expires: i.state.banExpireDays.map(futureDaysToUnixTime),
+            auth: auth().unwrap(),
+          });
+          WebSocketService.Instance.send(wsClient.banPerson(form));
+
+          i.state.showBanDialog = false;
+          i.setState(i.state);
+        },
+        none: void 0,
+      });
+  }
+
   parseMessage(msg: any) {
     let op = wsUserOp(msg);
     console.log(msg);
@@ -516,40 +805,53 @@ export class Profile extends Component<any, ProfileState> {
       // Since the PersonDetails contains posts/comments as well as some general user info we listen here as well
       // and set the parent state if it is not set or differs
       // TODO this might need to get abstracted
-      let data = wsJsonToRes<GetPersonDetailsResponse>(msg).data;
-      this.state.personRes = data;
-      console.log(data);
+      let data = wsJsonToRes<GetPersonDetailsResponse>(
+        msg,
+        GetPersonDetailsResponse
+      );
+      this.state.personRes = Some(data);
       this.state.loading = false;
+      this.setPersonBlock();
       this.setState(this.state);
       restoreScrollPosition(this.context);
     } else if (op == UserOperation.AddAdmin) {
-      let data = wsJsonToRes<AddAdminResponse>(msg).data;
+      let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
       this.state.siteRes.admins = data.admins;
       this.setState(this.state);
     } else if (op == UserOperation.CreateCommentLike) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      createCommentLikeRes(data.comment_view, this.state.personRes.comments);
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      createCommentLikeRes(
+        data.comment_view,
+        this.state.personRes.map(r => r.comments).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (
       op == UserOperation.EditComment ||
       op == UserOperation.DeleteComment ||
       op == UserOperation.RemoveComment
     ) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      editCommentRes(data.comment_view, this.state.personRes.comments);
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      editCommentRes(
+        data.comment_view,
+        this.state.personRes.map(r => r.comments).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (op == UserOperation.CreateComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      if (
-        UserService.Instance.myUserInfo &&
-        data.comment_view.creator.id ==
-          UserService.Instance.myUserInfo.local_user_view.person.id
-      ) {
-        toast(i18n.t("reply_sent"));
-      }
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          if (data.comment_view.creator.id == mui.local_user_view.person.id) {
+            toast(i18n.t("reply_sent"));
+          }
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.SaveComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      saveCommentRes(data.comment_view, this.state.personRes.comments);
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      saveCommentRes(
+        data.comment_view,
+        this.state.personRes.map(r => r.comments).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (
       op == UserOperation.EditPost ||
@@ -559,25 +861,54 @@ export class Profile extends Component<any, ProfileState> {
       op == UserOperation.StickyPost ||
       op == UserOperation.SavePost
     ) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      editPostFindRes(data.post_view, this.state.personRes.posts);
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      editPostFindRes(
+        data.post_view,
+        this.state.personRes.map(r => r.posts).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (op == UserOperation.CreatePostLike) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      createPostLikeFindRes(data.post_view, this.state.personRes.posts);
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      createPostLikeFindRes(
+        data.post_view,
+        this.state.personRes.map(r => r.posts).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (op == UserOperation.BanPerson) {
-      let data = wsJsonToRes<BanPersonResponse>(msg).data;
-      this.state.personRes.comments
-        .filter(c => c.creator.id == data.person_view.person.id)
-        .forEach(c => (c.creator.banned = data.banned));
-      this.state.personRes.posts
-        .filter(c => c.creator.id == data.person_view.person.id)
-        .forEach(c => (c.creator.banned = data.banned));
-      this.setState(this.state);
+      let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
+      this.state.personRes.match({
+        some: res => {
+          res.comments
+            .filter(c => c.creator.id == data.person_view.person.id)
+            .forEach(c => (c.creator.banned = data.banned));
+          res.posts
+            .filter(c => c.creator.id == data.person_view.person.id)
+            .forEach(c => (c.creator.banned = data.banned));
+          let pv = res.person_view;
+
+          if (pv.person.id == data.person_view.person.id) {
+            pv.person.banned = data.banned;
+          }
+          this.setState(this.state);
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.BlockPerson) {
-      let data = wsJsonToRes<BlockPersonResponse>(msg).data;
+      let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
       updatePersonBlock(data);
+      this.setPersonBlock();
+      this.setState(this.state);
+    } else if (
+      op == UserOperation.PurgePerson ||
+      op == UserOperation.PurgePost ||
+      op == UserOperation.PurgeComment ||
+      op == UserOperation.PurgeCommunity
+    ) {
+      let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+      if (data.success) {
+        toast(i18n.t("purge_success"));
+        this.context.router.history.push(`/`);
+      }
     }
   }
 }
diff --git a/src/shared/components/person/registration-applications.tsx b/src/shared/components/person/registration-applications.tsx
new file mode 100644 (file)
index 0000000..eec9031
--- /dev/null
@@ -0,0 +1,272 @@
+import { None, Option, Some } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
+import {
+  GetSiteResponse,
+  ListRegistrationApplications,
+  ListRegistrationApplicationsResponse,
+  RegistrationApplicationResponse,
+  UserOperation,
+  wsJsonToRes,
+  wsUserOp,
+} from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { InitialFetchRequest } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
+import {
+  auth,
+  fetchLimit,
+  isBrowser,
+  setIsoData,
+  setupTippy,
+  toast,
+  updateRegistrationApplicationRes,
+  wsClient,
+  wsSubscribe,
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { Paginator } from "../common/paginator";
+import { RegistrationApplication } from "../common/registration-application";
+
+enum UnreadOrAll {
+  Unread,
+  All,
+}
+
+interface RegistrationApplicationsState {
+  listRegistrationApplicationsResponse: Option<ListRegistrationApplicationsResponse>;
+  siteRes: GetSiteResponse;
+  unreadOrAll: UnreadOrAll;
+  page: number;
+  loading: boolean;
+}
+
+export class RegistrationApplications extends Component<
+  any,
+  RegistrationApplicationsState
+> {
+  private isoData = setIsoData(
+    this.context,
+    ListRegistrationApplicationsResponse
+  );
+  private subscription: Subscription;
+  private emptyState: RegistrationApplicationsState = {
+    listRegistrationApplicationsResponse: None,
+    siteRes: this.isoData.site_res,
+    unreadOrAll: UnreadOrAll.Unread,
+    page: 1,
+    loading: true,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+
+    this.state = this.emptyState;
+    this.handlePageChange = this.handlePageChange.bind(this);
+
+    if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+      toast(i18n.t("not_logged_in"), "danger");
+      this.context.router.history.push(`/login`);
+    }
+
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
+    // Only fetch the data if coming from another route
+    if (this.isoData.path == this.context.router.route.match.url) {
+      this.state.listRegistrationApplicationsResponse = Some(
+        this.isoData.routeData[0] as ListRegistrationApplicationsResponse
+      );
+      this.state.loading = false;
+    } else {
+      this.refetch();
+    }
+  }
+
+  componentDidMount() {
+    setupTippy();
+  }
+
+  componentWillUnmount() {
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
+  }
+
+  get documentTitle(): string {
+    return this.state.siteRes.site_view.match({
+      some: siteView =>
+        UserService.Instance.myUserInfo.match({
+          some: mui =>
+            `@${mui.local_user_view.person.name} ${i18n.t(
+              "registration_applications"
+            )} - ${siteView.site.name}`,
+          none: "",
+        }),
+      none: "",
+    });
+  }
+
+  render() {
+    return (
+      <div class="container">
+        {this.state.loading ? (
+          <h5>
+            <Spinner large />
+          </h5>
+        ) : (
+          <div class="row">
+            <div class="col-12">
+              <HtmlTags
+                title={this.documentTitle}
+                path={this.context.router.route.match.url}
+                description={None}
+                image={None}
+              />
+              <h5 class="mb-2">{i18n.t("registration_applications")}</h5>
+              {this.selects()}
+              {this.applicationList()}
+              <Paginator
+                page={this.state.page}
+                onChange={this.handlePageChange}
+              />
+            </div>
+          </div>
+        )}
+      </div>
+    );
+  }
+
+  unreadOrAllRadios() {
+    return (
+      <div class="btn-group btn-group-toggle flex-wrap mb-2">
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.unreadOrAll == UnreadOrAll.Unread && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={UnreadOrAll.Unread}
+            checked={this.state.unreadOrAll == UnreadOrAll.Unread}
+            onChange={linkEvent(this, this.handleUnreadOrAllChange)}
+          />
+          {i18n.t("unread")}
+        </label>
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.unreadOrAll == UnreadOrAll.All && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={UnreadOrAll.All}
+            checked={this.state.unreadOrAll == UnreadOrAll.All}
+            onChange={linkEvent(this, this.handleUnreadOrAllChange)}
+          />
+          {i18n.t("all")}
+        </label>
+      </div>
+    );
+  }
+
+  selects() {
+    return (
+      <div className="mb-2">
+        <span class="mr-3">{this.unreadOrAllRadios()}</span>
+      </div>
+    );
+  }
+
+  applicationList() {
+    return this.state.listRegistrationApplicationsResponse.match({
+      some: res => (
+        <div>
+          {res.registration_applications.map(ra => (
+            <>
+              <hr />
+              <RegistrationApplication
+                key={ra.registration_application.id}
+                application={ra}
+              />
+            </>
+          ))}
+        </div>
+      ),
+      none: <></>,
+    });
+  }
+
+  handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
+    i.state.unreadOrAll = Number(event.target.value);
+    i.state.page = 1;
+    i.setState(i.state);
+    i.refetch();
+  }
+
+  handlePageChange(page: number) {
+    this.setState({ page });
+    this.refetch();
+  }
+
+  static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
+    let promises: Promise<any>[] = [];
+
+    let form = new ListRegistrationApplications({
+      unread_only: Some(true),
+      page: Some(1),
+      limit: Some(fetchLimit),
+      auth: req.auth.unwrap(),
+    });
+    promises.push(req.client.listRegistrationApplications(form));
+
+    return promises;
+  }
+
+  refetch() {
+    let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread;
+    let form = new ListRegistrationApplications({
+      unread_only: Some(unread_only),
+      page: Some(this.state.page),
+      limit: Some(fetchLimit),
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.listRegistrationApplications(form));
+  }
+
+  parseMessage(msg: any) {
+    let op = wsUserOp(msg);
+    console.log(msg);
+    if (msg.error) {
+      toast(i18n.t(msg.error), "danger");
+      return;
+    } else if (msg.reconnect) {
+      this.refetch();
+    } else if (op == UserOperation.ListRegistrationApplications) {
+      let data = wsJsonToRes<ListRegistrationApplicationsResponse>(
+        msg,
+        ListRegistrationApplicationsResponse
+      );
+      this.state.listRegistrationApplicationsResponse = Some(data);
+      this.state.loading = false;
+      window.scrollTo(0, 0);
+      this.setState(this.state);
+    } else if (op == UserOperation.ApproveRegistrationApplication) {
+      let data = wsJsonToRes<RegistrationApplicationResponse>(
+        msg,
+        RegistrationApplicationResponse
+      );
+      updateRegistrationApplicationRes(
+        data.registration_application,
+        this.state.listRegistrationApplicationsResponse
+          .map(r => r.registration_applications)
+          .unwrapOr([])
+      );
+      let uacs = UserService.Instance.unreadApplicationCountSub;
+      // Minor bug, where if the application switches from deny to approve, the count will still go down
+      uacs.next(uacs.getValue() - 1);
+      this.setState(this.state);
+    }
+  }
+}
diff --git a/src/shared/components/person/reports.tsx b/src/shared/components/person/reports.tsx
new file mode 100644 (file)
index 0000000..f8a641b
--- /dev/null
@@ -0,0 +1,495 @@
+import { None, Option, Some } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
+import {
+  CommentReportResponse,
+  CommentReportView,
+  GetSiteResponse,
+  ListCommentReports,
+  ListCommentReportsResponse,
+  ListPostReports,
+  ListPostReportsResponse,
+  PostReportResponse,
+  PostReportView,
+  UserOperation,
+  wsJsonToRes,
+  wsUserOp,
+} from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { InitialFetchRequest } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
+import {
+  auth,
+  fetchLimit,
+  isBrowser,
+  setIsoData,
+  setupTippy,
+  toast,
+  updateCommentReportRes,
+  updatePostReportRes,
+  wsClient,
+  wsSubscribe,
+} from "../../utils";
+import { CommentReport } from "../comment/comment-report";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { Paginator } from "../common/paginator";
+import { PostReport } from "../post/post-report";
+
+enum UnreadOrAll {
+  Unread,
+  All,
+}
+
+enum MessageType {
+  All,
+  CommentReport,
+  PostReport,
+}
+
+enum MessageEnum {
+  CommentReport,
+  PostReport,
+}
+
+type ItemType = {
+  id: number;
+  type_: MessageEnum;
+  view: CommentReportView | PostReportView;
+  published: string;
+};
+
+interface ReportsState {
+  listCommentReportsResponse: Option<ListCommentReportsResponse>;
+  listPostReportsResponse: Option<ListPostReportsResponse>;
+  unreadOrAll: UnreadOrAll;
+  messageType: MessageType;
+  combined: ItemType[];
+  siteRes: GetSiteResponse;
+  page: number;
+  loading: boolean;
+}
+
+export class Reports extends Component<any, ReportsState> {
+  private isoData = setIsoData(
+    this.context,
+    ListCommentReportsResponse,
+    ListPostReportsResponse
+  );
+  private subscription: Subscription;
+  private emptyState: ReportsState = {
+    listCommentReportsResponse: None,
+    listPostReportsResponse: None,
+    unreadOrAll: UnreadOrAll.Unread,
+    messageType: MessageType.All,
+    combined: [],
+    page: 1,
+    siteRes: this.isoData.site_res,
+    loading: true,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+
+    this.state = this.emptyState;
+    this.handlePageChange = this.handlePageChange.bind(this);
+
+    if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
+      toast(i18n.t("not_logged_in"), "danger");
+      this.context.router.history.push(`/login`);
+    }
+
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
+    // Only fetch the data if coming from another route
+    if (this.isoData.path == this.context.router.route.match.url) {
+      this.state.listCommentReportsResponse = Some(
+        this.isoData.routeData[0] as ListCommentReportsResponse
+      );
+      this.state.listPostReportsResponse = Some(
+        this.isoData.routeData[1] as ListPostReportsResponse
+      );
+      this.state.combined = this.buildCombined();
+      this.state.loading = false;
+    } else {
+      this.refetch();
+    }
+  }
+
+  componentWillUnmount() {
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
+  }
+
+  get documentTitle(): string {
+    return this.state.siteRes.site_view.match({
+      some: siteView =>
+        UserService.Instance.myUserInfo.match({
+          some: mui =>
+            `@${mui.local_user_view.person.name} ${i18n.t("reports")} - ${
+              siteView.site.name
+            }`,
+          none: "",
+        }),
+      none: "",
+    });
+  }
+
+  render() {
+    return (
+      <div class="container">
+        {this.state.loading ? (
+          <h5>
+            <Spinner large />
+          </h5>
+        ) : (
+          <div class="row">
+            <div class="col-12">
+              <HtmlTags
+                title={this.documentTitle}
+                path={this.context.router.route.match.url}
+                description={None}
+                image={None}
+              />
+              <h5 class="mb-2">{i18n.t("reports")}</h5>
+              {this.selects()}
+              {this.state.messageType == MessageType.All && this.all()}
+              {this.state.messageType == MessageType.CommentReport &&
+                this.commentReports()}
+              {this.state.messageType == MessageType.PostReport &&
+                this.postReports()}
+              <Paginator
+                page={this.state.page}
+                onChange={this.handlePageChange}
+              />
+            </div>
+          </div>
+        )}
+      </div>
+    );
+  }
+
+  unreadOrAllRadios() {
+    return (
+      <div class="btn-group btn-group-toggle flex-wrap mb-2">
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.unreadOrAll == UnreadOrAll.Unread && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={UnreadOrAll.Unread}
+            checked={this.state.unreadOrAll == UnreadOrAll.Unread}
+            onChange={linkEvent(this, this.handleUnreadOrAllChange)}
+          />
+          {i18n.t("unread")}
+        </label>
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.unreadOrAll == UnreadOrAll.All && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={UnreadOrAll.All}
+            checked={this.state.unreadOrAll == UnreadOrAll.All}
+            onChange={linkEvent(this, this.handleUnreadOrAllChange)}
+          />
+          {i18n.t("all")}
+        </label>
+      </div>
+    );
+  }
+
+  messageTypeRadios() {
+    return (
+      <div class="btn-group btn-group-toggle flex-wrap mb-2">
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.messageType == MessageType.All && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={MessageType.All}
+            checked={this.state.messageType == MessageType.All}
+            onChange={linkEvent(this, this.handleMessageTypeChange)}
+          />
+          {i18n.t("all")}
+        </label>
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.messageType == MessageType.CommentReport && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={MessageType.CommentReport}
+            checked={this.state.messageType == MessageType.CommentReport}
+            onChange={linkEvent(this, this.handleMessageTypeChange)}
+          />
+          {i18n.t("comments")}
+        </label>
+        <label
+          className={`btn btn-outline-secondary pointer
+            ${this.state.messageType == MessageType.PostReport && "active"}
+          `}
+        >
+          <input
+            type="radio"
+            value={MessageType.PostReport}
+            checked={this.state.messageType == MessageType.PostReport}
+            onChange={linkEvent(this, this.handleMessageTypeChange)}
+          />
+          {i18n.t("posts")}
+        </label>
+      </div>
+    );
+  }
+
+  selects() {
+    return (
+      <div className="mb-2">
+        <span class="mr-3">{this.unreadOrAllRadios()}</span>
+        <span class="mr-3">{this.messageTypeRadios()}</span>
+      </div>
+    );
+  }
+
+  replyToReplyType(r: CommentReportView): ItemType {
+    return {
+      id: r.comment_report.id,
+      type_: MessageEnum.CommentReport,
+      view: r,
+      published: r.comment_report.published,
+    };
+  }
+
+  mentionToReplyType(r: PostReportView): ItemType {
+    return {
+      id: r.post_report.id,
+      type_: MessageEnum.PostReport,
+      view: r,
+      published: r.post_report.published,
+    };
+  }
+
+  buildCombined(): ItemType[] {
+    let comments: ItemType[] = this.state.listCommentReportsResponse
+      .map(r => r.comment_reports)
+      .unwrapOr([])
+      .map(r => this.replyToReplyType(r));
+    let posts: ItemType[] = this.state.listPostReportsResponse
+      .map(r => r.post_reports)
+      .unwrapOr([])
+      .map(r => this.mentionToReplyType(r));
+
+    return [...comments, ...posts].sort((a, b) =>
+      b.published.localeCompare(a.published)
+    );
+  }
+
+  renderItemType(i: ItemType) {
+    switch (i.type_) {
+      case MessageEnum.CommentReport:
+        return (
+          <CommentReport key={i.id} report={i.view as CommentReportView} />
+        );
+      case MessageEnum.PostReport:
+        return <PostReport key={i.id} report={i.view as PostReportView} />;
+      default:
+        return <div />;
+    }
+  }
+
+  all() {
+    return (
+      <div>
+        {this.state.combined.map(i => (
+          <>
+            <hr />
+            {this.renderItemType(i)}
+          </>
+        ))}
+      </div>
+    );
+  }
+
+  commentReports() {
+    return this.state.listCommentReportsResponse.match({
+      some: res => (
+        <div>
+          {res.comment_reports.map(cr => (
+            <>
+              <hr />
+              <CommentReport key={cr.comment_report.id} report={cr} />
+            </>
+          ))}
+        </div>
+      ),
+      none: <></>,
+    });
+  }
+
+  postReports() {
+    return this.state.listPostReportsResponse.match({
+      some: res => (
+        <div>
+          {res.post_reports.map(pr => (
+            <>
+              <hr />
+              <PostReport key={pr.post_report.id} report={pr} />
+            </>
+          ))}
+        </div>
+      ),
+      none: <></>,
+    });
+  }
+
+  handlePageChange(page: number) {
+    this.setState({ page });
+    this.refetch();
+  }
+
+  handleUnreadOrAllChange(i: Reports, event: any) {
+    i.state.unreadOrAll = Number(event.target.value);
+    i.state.page = 1;
+    i.setState(i.state);
+    i.refetch();
+  }
+
+  handleMessageTypeChange(i: Reports, event: any) {
+    i.state.messageType = Number(event.target.value);
+    i.state.page = 1;
+    i.setState(i.state);
+    i.refetch();
+  }
+
+  static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
+    let promises: Promise<any>[] = [];
+
+    let unresolved_only = Some(true);
+    let page = Some(1);
+    let limit = Some(fetchLimit);
+    let community_id = None;
+    let auth = req.auth.unwrap();
+
+    let commentReportsForm = new ListCommentReports({
+      // TODO community_id
+      unresolved_only,
+      community_id,
+      page,
+      limit,
+      auth,
+    });
+    promises.push(req.client.listCommentReports(commentReportsForm));
+
+    let postReportsForm = new ListPostReports({
+      // TODO community_id
+      unresolved_only,
+      community_id,
+      page,
+      limit,
+      auth,
+    });
+    promises.push(req.client.listPostReports(postReportsForm));
+
+    return promises;
+  }
+
+  refetch() {
+    let unresolved_only = Some(this.state.unreadOrAll == UnreadOrAll.Unread);
+    let community_id = None;
+    let page = Some(this.state.page);
+    let limit = Some(fetchLimit);
+
+    let commentReportsForm = new ListCommentReports({
+      unresolved_only,
+      // TODO community_id
+      community_id,
+      page,
+      limit,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(
+      wsClient.listCommentReports(commentReportsForm)
+    );
+
+    let postReportsForm = new ListPostReports({
+      unresolved_only,
+      // TODO community_id
+      community_id,
+      page,
+      limit,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.listPostReports(postReportsForm));
+  }
+
+  parseMessage(msg: any) {
+    let op = wsUserOp(msg);
+    console.log(msg);
+    if (msg.error) {
+      toast(i18n.t(msg.error), "danger");
+      return;
+    } else if (msg.reconnect) {
+      this.refetch();
+    } else if (op == UserOperation.ListCommentReports) {
+      let data = wsJsonToRes<ListCommentReportsResponse>(
+        msg,
+        ListCommentReportsResponse
+      );
+      this.state.listCommentReportsResponse = Some(data);
+      this.state.combined = this.buildCombined();
+      this.state.loading = false;
+      // this.sendUnreadCount();
+      window.scrollTo(0, 0);
+      this.setState(this.state);
+      setupTippy();
+    } else if (op == UserOperation.ListPostReports) {
+      let data = wsJsonToRes<ListPostReportsResponse>(
+        msg,
+        ListPostReportsResponse
+      );
+      this.state.listPostReportsResponse = Some(data);
+      this.state.combined = this.buildCombined();
+      this.state.loading = false;
+      // this.sendUnreadCount();
+      window.scrollTo(0, 0);
+      this.setState(this.state);
+      setupTippy();
+    } else if (op == UserOperation.ResolvePostReport) {
+      let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+      updatePostReportRes(
+        data.post_report_view,
+        this.state.listPostReportsResponse.map(r => r.post_reports).unwrapOr([])
+      );
+      let urcs = UserService.Instance.unreadReportCountSub;
+      if (data.post_report_view.post_report.resolved) {
+        urcs.next(urcs.getValue() - 1);
+      } else {
+        urcs.next(urcs.getValue() + 1);
+      }
+      this.setState(this.state);
+    } else if (op == UserOperation.ResolveCommentReport) {
+      let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+      updateCommentReportRes(
+        data.comment_report_view,
+        this.state.listCommentReportsResponse
+          .map(r => r.comment_reports)
+          .unwrapOr([])
+      );
+      let urcs = UserService.Instance.unreadReportCountSub;
+      if (data.comment_report_view.comment_report.resolved) {
+        urcs.next(urcs.getValue() - 1);
+      } else {
+        urcs.next(urcs.getValue() + 1);
+      }
+      this.setState(this.state);
+    }
+  }
+}
index 955cc30184fe8196a8bc5c607b3bc5e35c13449d..532d92204ab9ae624a24e586b7d1a35a5cff1bc2 100644 (file)
@@ -1,5 +1,5 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
-import ISO6391 from "iso-639-1";
 import {
   BlockCommunity,
   BlockCommunityResponse,
@@ -16,38 +16,40 @@ import {
   PersonViewSafe,
   SaveUserSettings,
   SortType,
+  toUndefined,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
-import { i18n } from "../../i18next";
+import { i18n, languages } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
   choicesConfig,
   communitySelectName,
   communityToChoice,
   debounce,
   elementUrl,
+  enableNsfw,
   fetchCommunities,
+  fetchThemeList,
   fetchUsers,
-  getLanguage,
+  getLanguages,
   isBrowser,
-  languages,
   personSelectName,
   personToChoice,
+  relTags,
   setIsoData,
   setTheme,
   setupTippy,
   showLocal,
-  themes,
   toast,
   updateCommunityBlock,
   updatePersonBlock,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Icon, Spinner } from "../common/icon";
@@ -66,18 +68,18 @@ if (isBrowser()) {
 interface SettingsState {
   saveUserSettingsForm: SaveUserSettings;
   changePasswordForm: ChangePassword;
-  saveUserSettingsLoading: boolean;
-  changePasswordLoading: boolean;
-  deleteAccountLoading: boolean;
-  deleteAccountShowConfirm: boolean;
   deleteAccountForm: DeleteAccount;
   personBlocks: PersonBlockView[];
-  blockPersonId: number;
-  blockPerson?: PersonViewSafe;
+  blockPerson: Option<PersonViewSafe>;
   communityBlocks: CommunityBlockView[];
   blockCommunityId: number;
   blockCommunity?: CommunityView;
   currentTab: string;
+  themeList: string[];
+  saveUserSettingsLoading: boolean;
+  changePasswordLoading: boolean;
+  deleteAccountLoading: boolean;
+  deleteAccountShowConfirm: boolean;
   siteRes: GetSiteResponse;
 }
 
@@ -87,29 +89,48 @@ export class Settings extends Component<any, SettingsState> {
   private blockCommunityChoices: any;
   private subscription: Subscription;
   private emptyState: SettingsState = {
-    saveUserSettingsForm: {
-      auth: authField(false),
-    },
-    changePasswordForm: {
-      new_password: null,
-      new_password_verify: null,
-      old_password: null,
-      auth: authField(false),
-    },
-    saveUserSettingsLoading: null,
+    saveUserSettingsForm: new SaveUserSettings({
+      show_nsfw: None,
+      show_scores: None,
+      show_avatars: None,
+      show_read_posts: None,
+      show_bot_accounts: None,
+      show_new_post_notifs: None,
+      default_sort_type: None,
+      default_listing_type: None,
+      theme: None,
+      lang: None,
+      avatar: None,
+      banner: None,
+      display_name: None,
+      email: None,
+      bio: None,
+      matrix_user_id: None,
+      send_notifications_to_email: None,
+      bot_account: None,
+      auth: undefined,
+    }),
+    changePasswordForm: new ChangePassword({
+      new_password: undefined,
+      new_password_verify: undefined,
+      old_password: undefined,
+      auth: undefined,
+    }),
+    saveUserSettingsLoading: false,
     changePasswordLoading: false,
-    deleteAccountLoading: null,
+    deleteAccountLoading: false,
     deleteAccountShowConfirm: false,
-    deleteAccountForm: {
-      password: null,
-      auth: authField(false),
-    },
+    deleteAccountForm: new DeleteAccount({
+      password: undefined,
+      auth: undefined,
+    }),
     personBlocks: [],
-    blockPersonId: 0,
+    blockPerson: None,
     communityBlocks: [],
     blockCommunityId: 0,
     currentTab: "settings",
     siteRes: this.isoData.site_res,
+    themeList: [],
   };
 
   constructor(props: any, context: any) {
@@ -130,8 +151,12 @@ export class Settings extends Component<any, SettingsState> {
     this.subscription = wsSubscribe(this.parseMessage);
 
     this.setUserInfo();
+  }
 
+  async componentDidMount() {
     setupTippy();
+    this.state.themeList = await fetchThemeList();
+    this.setState(this.state);
   }
 
   componentWillUnmount() {
@@ -149,7 +174,7 @@ export class Settings extends Component<any, SettingsState> {
           <HtmlTags
             title={this.documentTitle}
             path={this.context.router.route.match.url}
-            description={this.documentTitle}
+            description={Some(this.documentTitle)}
             image={this.state.saveUserSettingsForm.avatar}
           />
           <ul class="nav nav-tabs mb-2">
@@ -227,10 +252,10 @@ export class Settings extends Component<any, SettingsState> {
         <h5>{i18n.t("change_password")}</h5>
         <form onSubmit={linkEvent(this, this.handleChangePasswordSubmit)}>
           <div class="form-group row">
-            <label class="col-lg-5 col-form-label" htmlFor="user-password">
+            <label class="col-sm-5 col-form-label" htmlFor="user-password">
               {i18n.t("new_password")}
             </label>
-            <div class="col-lg-7">
+            <div class="col-sm-7">
               <input
                 type="password"
                 id="user-password"
@@ -244,12 +269,12 @@ export class Settings extends Component<any, SettingsState> {
           </div>
           <div class="form-group row">
             <label
-              class="col-lg-5 col-form-label"
+              class="col-sm-5 col-form-label"
               htmlFor="user-verify-password"
             >
               {i18n.t("verify_password")}
             </label>
-            <div class="col-lg-7">
+            <div class="col-sm-7">
               <input
                 type="password"
                 id="user-verify-password"
@@ -262,10 +287,10 @@ export class Settings extends Component<any, SettingsState> {
             </div>
           </div>
           <div class="form-group row">
-            <label class="col-lg-5 col-form-label" htmlFor="user-old-password">
+            <label class="col-sm-5 col-form-label" htmlFor="user-old-password">
               {i18n.t("old_password")}
             </label>
-            <div class="col-lg-7">
+            <div class="col-sm-7">
               <input
                 type="password"
                 id="user-old-password"
@@ -337,14 +362,17 @@ export class Settings extends Component<any, SettingsState> {
           <select
             class="form-control"
             id="block-person-filter"
-            value={this.state.blockPersonId}
+            value={this.state.blockPerson.map(p => p.person.id).unwrapOr(0)}
           >
             <option value="0">—</option>
-            {this.state.blockPerson && (
-              <option value={this.state.blockPerson.person.id}>
-                {personSelectName(this.state.blockPerson)}
-              </option>
-            )}
+            {this.state.blockPerson.match({
+              some: personView => (
+                <option value={personView.person.id}>
+                  {personSelectName(personView)}
+                </option>
+              ),
+              none: <></>,
+            })}
           </select>
         </div>
       </div>
@@ -417,16 +445,18 @@ export class Settings extends Component<any, SettingsState> {
         <h5>{i18n.t("settings")}</h5>
         <form onSubmit={linkEvent(this, this.handleSaveSettingsSubmit)}>
           <div class="form-group row">
-            <label class="col-lg-5 col-form-label" htmlFor="display-name">
+            <label class="col-sm-5 col-form-label" htmlFor="display-name">
               {i18n.t("display_name")}
             </label>
-            <div class="col-lg-7">
+            <div class="col-sm-7">
               <input
                 id="display-name"
                 type="text"
                 class="form-control"
                 placeholder={i18n.t("optional")}
-                value={this.state.saveUserSettingsForm.display_name}
+                value={toUndefined(
+                  this.state.saveUserSettingsForm.display_name
+                )}
                 onInput={linkEvent(this, this.handleDisplayNameChange)}
                 pattern="^(?!@)(.+)$"
                 minLength={3}
@@ -434,145 +464,168 @@ export class Settings extends Component<any, SettingsState> {
             </div>
           </div>
           <div class="form-group row">
-            <label class="col-lg-3 col-form-label" htmlFor="user-bio">
+            <label class="col-sm-3 col-form-label" htmlFor="user-bio">
               {i18n.t("bio")}
             </label>
-            <div class="col-lg-9">
+            <div class="col-sm-9">
               <MarkdownTextArea
                 initialContent={this.state.saveUserSettingsForm.bio}
                 onContentChange={this.handleBioChange}
-                maxLength={300}
+                maxLength={Some(300)}
+                placeholder={None}
+                buttonTitle={None}
                 hideNavigationWarnings
               />
             </div>
           </div>
           <div class="form-group row">
-            <label class="col-lg-3 col-form-label" htmlFor="user-email">
+            <label class="col-sm-3 col-form-label" htmlFor="user-email">
               {i18n.t("email")}
             </label>
-            <div class="col-lg-9">
+            <div class="col-sm-9">
               <input
                 type="email"
                 id="user-email"
                 class="form-control"
                 placeholder={i18n.t("optional")}
-                value={this.state.saveUserSettingsForm.email}
+                value={toUndefined(this.state.saveUserSettingsForm.email)}
                 onInput={linkEvent(this, this.handleEmailChange)}
                 minLength={3}
               />
             </div>
           </div>
           <div class="form-group row">
-            <label class="col-lg-5 col-form-label" htmlFor="matrix-user-id">
-              <a href={elementUrl} rel="noopener">
+            <label class="col-sm-5 col-form-label" htmlFor="matrix-user-id">
+              <a href={elementUrl} rel={relTags}>
                 {i18n.t("matrix_user_id")}
               </a>
             </label>
-            <div class="col-lg-7">
+            <div class="col-sm-7">
               <input
                 id="matrix-user-id"
                 type="text"
                 class="form-control"
                 placeholder="@user:example.com"
-                value={this.state.saveUserSettingsForm.matrix_user_id}
+                value={toUndefined(
+                  this.state.saveUserSettingsForm.matrix_user_id
+                )}
                 onInput={linkEvent(this, this.handleMatrixUserIdChange)}
                 pattern="^@[A-Za-z0-9._=-]+:[A-Za-z0-9.-]+\.[A-Za-z]{2,}$"
               />
             </div>
           </div>
-          <div class="form-group">
-            <label>{i18n.t("avatar")}</label>
-            <ImageUploadForm
-              uploadTitle={i18n.t("upload_avatar")}
-              imageSrc={this.state.saveUserSettingsForm.avatar}
-              onUpload={this.handleAvatarUpload}
-              onRemove={this.handleAvatarRemove}
-              rounded
-            />
+          <div class="form-group row">
+            <label class="col-sm-3">{i18n.t("avatar")}</label>
+            <div class="col-sm-9">
+              <ImageUploadForm
+                uploadTitle={i18n.t("upload_avatar")}
+                imageSrc={this.state.saveUserSettingsForm.avatar}
+                onUpload={this.handleAvatarUpload}
+                onRemove={this.handleAvatarRemove}
+                rounded
+              />
+            </div>
           </div>
-          <div class="form-group">
-            <label>{i18n.t("banner")}</label>
-            <ImageUploadForm
-              uploadTitle={i18n.t("upload_banner")}
-              imageSrc={this.state.saveUserSettingsForm.banner}
-              onUpload={this.handleBannerUpload}
-              onRemove={this.handleBannerRemove}
-            />
+          <div class="form-group row">
+            <label class="col-sm-3">{i18n.t("banner")}</label>
+            <div class="col-sm-9">
+              <ImageUploadForm
+                uploadTitle={i18n.t("upload_banner")}
+                imageSrc={this.state.saveUserSettingsForm.banner}
+                onUpload={this.handleBannerUpload}
+                onRemove={this.handleBannerRemove}
+              />
+            </div>
           </div>
-          <div class="form-group">
-            <label htmlFor="user-language">{i18n.t("language")}</label>
-            <select
-              id="user-language"
-              value={this.state.saveUserSettingsForm.lang}
-              onChange={linkEvent(this, this.handleLangChange)}
-              class="ml-2 custom-select w-auto"
-            >
-              <option disabled aria-hidden="true">
-                {i18n.t("language")}
-              </option>
-              <option value="browser">{i18n.t("browser_default")}</option>
-              <option disabled aria-hidden="true">
-                ──
-              </option>
-              {languages.sort().map(lang => (
-                <option value={lang.code}>
-                  {ISO6391.getNativeName(lang.code) || lang.code}
+          <div class="form-group row">
+            <label class="col-sm-3" htmlFor="user-language">
+              {i18n.t("language")}
+            </label>
+            <div class="col-sm-9">
+              <select
+                id="user-language"
+                value={toUndefined(this.state.saveUserSettingsForm.lang)}
+                onChange={linkEvent(this, this.handleLangChange)}
+                class="custom-select w-auto"
+              >
+                <option disabled aria-hidden="true">
+                  {i18n.t("language")}
                 </option>
-              ))}
-            </select>
-          </div>
-          <div class="form-group">
-            <label htmlFor="user-theme">{i18n.t("theme")}</label>
-            <select
-              id="user-theme"
-              value={this.state.saveUserSettingsForm.theme}
-              onChange={linkEvent(this, this.handleThemeChange)}
-              class="ml-2 custom-select w-auto"
-            >
-              <option disabled aria-hidden="true">
-                {i18n.t("theme")}
-              </option>
-              <option value="browser">{i18n.t("browser_default")}</option>
-              {themes.map(theme => (
-                <option value={theme}>{theme}</option>
-              ))}
-            </select>
+                <option value="browser">{i18n.t("browser_default")}</option>
+                <option disabled aria-hidden="true">
+                  ──
+                </option>
+                {languages
+                  .sort((a, b) => a.code.localeCompare(b.code))
+                  .map(lang => (
+                    <option value={lang.code}>{lang.name}</option>
+                  ))}
+              </select>
+            </div>
           </div>
-          <form className="form-group">
-            <label>
-              <div class="mr-2">{i18n.t("type")}</div>
+          <div class="form-group row">
+            <label class="col-sm-3" htmlFor="user-theme">
+              {i18n.t("theme")}
             </label>
-            <ListingTypeSelect
-              type_={
-                Object.values(ListingType)[
-                  this.state.saveUserSettingsForm.default_listing_type
-                ]
-              }
-              showLocal={showLocal(this.isoData)}
-              onChange={this.handleListingTypeChange}
-            />
+            <div class="col-sm-9">
+              <select
+                id="user-theme"
+                value={toUndefined(this.state.saveUserSettingsForm.theme)}
+                onChange={linkEvent(this, this.handleThemeChange)}
+                class="custom-select w-auto"
+              >
+                <option disabled aria-hidden="true">
+                  {i18n.t("theme")}
+                </option>
+                <option value="browser">{i18n.t("browser_default")}</option>
+                {this.state.themeList.map(theme => (
+                  <option value={theme}>{theme}</option>
+                ))}
+              </select>
+            </div>
+          </div>
+          <form className="form-group row">
+            <label class="col-sm-3">{i18n.t("type")}</label>
+            <div class="col-sm-9">
+              <ListingTypeSelect
+                type_={
+                  Object.values(ListingType)[
+                    this.state.saveUserSettingsForm.default_listing_type.unwrapOr(
+                      1
+                    )
+                  ]
+                }
+                showLocal={showLocal(this.isoData)}
+                showSubscribed
+                onChange={this.handleListingTypeChange}
+              />
+            </div>
           </form>
-          <form className="form-group">
-            <label>
-              <div class="mr-2">{i18n.t("sort_type")}</div>
-            </label>
-            <SortSelect
-              sort={
-                Object.values(SortType)[
-                  this.state.saveUserSettingsForm.default_sort_type
-                ]
-              }
-              onChange={this.handleSortTypeChange}
-            />
+          <form className="form-group row">
+            <label class="col-sm-3">{i18n.t("sort_type")}</label>
+            <div class="col-sm-9">
+              <SortSelect
+                sort={
+                  Object.values(SortType)[
+                    this.state.saveUserSettingsForm.default_sort_type.unwrapOr(
+                      0
+                    )
+                  ]
+                }
+                onChange={this.handleSortTypeChange}
+              />
+            </div>
           </form>
-          {this.state.siteRes.site_view.site.enable_nsfw && (
+          {enableNsfw(this.state.siteRes) && (
             <div class="form-group">
               <div class="form-check">
                 <input
                   class="form-check-input"
                   id="user-show-nsfw"
                   type="checkbox"
-                  checked={this.state.saveUserSettingsForm.show_nsfw}
+                  checked={toUndefined(
+                    this.state.saveUserSettingsForm.show_nsfw
+                  )}
                   onChange={linkEvent(this, this.handleShowNsfwChange)}
                 />
                 <label class="form-check-label" htmlFor="user-show-nsfw">
@@ -587,7 +640,9 @@ export class Settings extends Component<any, SettingsState> {
                 class="form-check-input"
                 id="user-show-scores"
                 type="checkbox"
-                checked={this.state.saveUserSettingsForm.show_scores}
+                checked={toUndefined(
+                  this.state.saveUserSettingsForm.show_scores
+                )}
                 onChange={linkEvent(this, this.handleShowScoresChange)}
               />
               <label class="form-check-label" htmlFor="user-show-scores">
@@ -601,7 +656,9 @@ export class Settings extends Component<any, SettingsState> {
                 class="form-check-input"
                 id="user-show-avatars"
                 type="checkbox"
-                checked={this.state.saveUserSettingsForm.show_avatars}
+                checked={toUndefined(
+                  this.state.saveUserSettingsForm.show_avatars
+                )}
                 onChange={linkEvent(this, this.handleShowAvatarsChange)}
               />
               <label class="form-check-label" htmlFor="user-show-avatars">
@@ -615,7 +672,9 @@ export class Settings extends Component<any, SettingsState> {
                 class="form-check-input"
                 id="user-bot-account"
                 type="checkbox"
-                checked={this.state.saveUserSettingsForm.bot_account}
+                checked={toUndefined(
+                  this.state.saveUserSettingsForm.bot_account
+                )}
                 onChange={linkEvent(this, this.handleBotAccount)}
               />
               <label class="form-check-label" htmlFor="user-bot-account">
@@ -629,7 +688,9 @@ export class Settings extends Component<any, SettingsState> {
                 class="form-check-input"
                 id="user-show-bot-accounts"
                 type="checkbox"
-                checked={this.state.saveUserSettingsForm.show_bot_accounts}
+                checked={toUndefined(
+                  this.state.saveUserSettingsForm.show_bot_accounts
+                )}
                 onChange={linkEvent(this, this.handleShowBotAccounts)}
               />
               <label class="form-check-label" htmlFor="user-show-bot-accounts">
@@ -643,7 +704,9 @@ export class Settings extends Component<any, SettingsState> {
                 class="form-check-input"
                 id="user-show-read-posts"
                 type="checkbox"
-                checked={this.state.saveUserSettingsForm.show_read_posts}
+                checked={toUndefined(
+                  this.state.saveUserSettingsForm.show_read_posts
+                )}
                 onChange={linkEvent(this, this.handleReadPosts)}
               />
               <label class="form-check-label" htmlFor="user-show-read-posts">
@@ -657,7 +720,9 @@ export class Settings extends Component<any, SettingsState> {
                 class="form-check-input"
                 id="user-show-new-post-notifs"
                 type="checkbox"
-                checked={this.state.saveUserSettingsForm.show_new_post_notifs}
+                checked={toUndefined(
+                  this.state.saveUserSettingsForm.show_new_post_notifs
+                )}
                 onChange={linkEvent(this, this.handleShowNewPostNotifs)}
               />
               <label
@@ -675,9 +740,9 @@ export class Settings extends Component<any, SettingsState> {
                 id="user-send-notifications-to-email"
                 type="checkbox"
                 disabled={!this.state.saveUserSettingsForm.email}
-                checked={
+                checked={toUndefined(
                   this.state.saveUserSettingsForm.send_notifications_to_email
-                }
+                )}
                 onChange={linkEvent(
                   this,
                   this.handleSendNotificationsToEmailChange
@@ -770,10 +835,19 @@ export class Settings extends Component<any, SettingsState> {
         this.blockPersonChoices.passedElement.element.addEventListener(
           "search",
           debounce(async (e: any) => {
-            let persons = (await fetchUsers(e.detail.value)).users;
-            let choices = persons.map(pvs => personToChoice(pvs));
-            this.blockPersonChoices.setChoices(choices, "value", "label", true);
-          }, 400),
+            try {
+              let persons = (await fetchUsers(e.detail.value)).users;
+              let choices = persons.map(pvs => personToChoice(pvs));
+              this.blockPersonChoices.setChoices(
+                choices,
+                "value",
+                "label",
+                true
+              );
+            } catch (err) {
+              console.error(err);
+            }
+          }),
           false
         );
       }
@@ -795,16 +869,20 @@ export class Settings extends Component<any, SettingsState> {
         this.blockCommunityChoices.passedElement.element.addEventListener(
           "search",
           debounce(async (e: any) => {
-            let communities = (await fetchCommunities(e.detail.value))
-              .communities;
-            let choices = communities.map(cv => communityToChoice(cv));
-            this.blockCommunityChoices.setChoices(
-              choices,
-              "value",
-              "label",
-              true
-            );
-          }, 400),
+            try {
+              let communities = (await fetchCommunities(e.detail.value))
+                .communities;
+              let choices = communities.map(cv => communityToChoice(cv));
+              this.blockCommunityChoices.setChoices(
+                choices,
+                "value",
+                "label",
+                true
+              );
+            } catch (err) {
+              console.log(err);
+            }
+          }),
           false
         );
       }
@@ -813,31 +891,31 @@ export class Settings extends Component<any, SettingsState> {
 
   handleBlockPerson(personId: number) {
     if (personId != 0) {
-      let blockUserForm: BlockPerson = {
+      let blockUserForm = new BlockPerson({
         person_id: personId,
         block: true,
-        auth: authField(),
-      };
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
     }
   }
 
   handleUnblockPerson(i: { ctx: Settings; recipientId: number }) {
-    let blockUserForm: BlockPerson = {
+    let blockUserForm = new BlockPerson({
       person_id: i.recipientId,
       block: false,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
   }
 
   handleBlockCommunity(community_id: number) {
     if (community_id != 0) {
-      let blockCommunityForm: BlockCommunity = {
+      let blockCommunityForm = new BlockCommunity({
         community_id,
         block: true,
-        auth: authField(),
-      };
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(
         wsClient.blockCommunity(blockCommunityForm)
       );
@@ -845,126 +923,133 @@ export class Settings extends Component<any, SettingsState> {
   }
 
   handleUnblockCommunity(i: { ctx: Settings; communityId: number }) {
-    let blockCommunityForm: BlockCommunity = {
+    let blockCommunityForm = new BlockCommunity({
       community_id: i.communityId,
       block: false,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.blockCommunity(blockCommunityForm));
   }
 
   handleShowNsfwChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.show_nsfw = event.target.checked;
+    i.state.saveUserSettingsForm.show_nsfw = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleShowAvatarsChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.show_avatars = event.target.checked;
-    UserService.Instance.myUserInfo.local_user_view.local_user.show_avatars =
-      event.target.checked; // Just for instant updates
+    i.state.saveUserSettingsForm.show_avatars = Some(event.target.checked);
+    UserService.Instance.myUserInfo.match({
+      some: mui =>
+        (mui.local_user_view.local_user.show_avatars = event.target.checked),
+      none: void 0,
+    });
     i.setState(i.state);
   }
 
   handleBotAccount(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.bot_account = event.target.checked;
+    i.state.saveUserSettingsForm.bot_account = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleShowBotAccounts(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.show_bot_accounts = event.target.checked;
+    i.state.saveUserSettingsForm.show_bot_accounts = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleReadPosts(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.show_read_posts = event.target.checked;
+    i.state.saveUserSettingsForm.show_read_posts = Some(event.target.checked);
     i.setState(i.state);
   }
 
   handleShowNewPostNotifs(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.show_new_post_notifs = event.target.checked;
+    i.state.saveUserSettingsForm.show_new_post_notifs = Some(
+      event.target.checked
+    );
     i.setState(i.state);
   }
 
   handleShowScoresChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.show_scores = event.target.checked;
-    UserService.Instance.myUserInfo.local_user_view.local_user.show_scores =
-      event.target.checked; // Just for instant updates
+    i.state.saveUserSettingsForm.show_scores = Some(event.target.checked);
+    UserService.Instance.myUserInfo.match({
+      some: mui =>
+        (mui.local_user_view.local_user.show_scores = event.target.checked),
+      none: void 0,
+    });
     i.setState(i.state);
   }
 
   handleSendNotificationsToEmailChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.send_notifications_to_email =
-      event.target.checked;
+    i.state.saveUserSettingsForm.send_notifications_to_email = Some(
+      event.target.checked
+    );
     i.setState(i.state);
   }
 
   handleThemeChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.theme = event.target.value;
+    i.state.saveUserSettingsForm.theme = Some(event.target.value);
     setTheme(event.target.value, true);
     i.setState(i.state);
   }
 
   handleLangChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.lang = event.target.value;
-    i18n.changeLanguage(getLanguage(i.state.saveUserSettingsForm.lang));
+    i.state.saveUserSettingsForm.lang = Some(event.target.value);
+    i18n.changeLanguage(
+      getLanguages(i.state.saveUserSettingsForm.lang.unwrap())[0]
+    );
     i.setState(i.state);
   }
 
   handleSortTypeChange(val: SortType) {
-    this.state.saveUserSettingsForm.default_sort_type =
-      Object.keys(SortType).indexOf(val);
+    this.state.saveUserSettingsForm.default_sort_type = Some(
+      Object.keys(SortType).indexOf(val)
+    );
     this.setState(this.state);
   }
 
   handleListingTypeChange(val: ListingType) {
-    this.state.saveUserSettingsForm.default_listing_type =
-      Object.keys(ListingType).indexOf(val);
+    this.state.saveUserSettingsForm.default_listing_type = Some(
+      Object.keys(ListingType).indexOf(val)
+    );
     this.setState(this.state);
   }
 
   handleEmailChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.email = event.target.value;
+    i.state.saveUserSettingsForm.email = Some(event.target.value);
     i.setState(i.state);
   }
 
   handleBioChange(val: string) {
-    this.state.saveUserSettingsForm.bio = val;
+    this.state.saveUserSettingsForm.bio = Some(val);
     this.setState(this.state);
   }
 
   handleAvatarUpload(url: string) {
-    this.state.saveUserSettingsForm.avatar = url;
+    this.state.saveUserSettingsForm.avatar = Some(url);
     this.setState(this.state);
   }
 
   handleAvatarRemove() {
-    this.state.saveUserSettingsForm.avatar = "";
+    this.state.saveUserSettingsForm.avatar = Some("");
     this.setState(this.state);
   }
 
   handleBannerUpload(url: string) {
-    this.state.saveUserSettingsForm.banner = url;
+    this.state.saveUserSettingsForm.banner = Some(url);
     this.setState(this.state);
   }
 
   handleBannerRemove() {
-    this.state.saveUserSettingsForm.banner = "";
+    this.state.saveUserSettingsForm.banner = Some("");
     this.setState(this.state);
   }
 
   handleDisplayNameChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.display_name = event.target.value;
+    i.state.saveUserSettingsForm.display_name = Some(event.target.value);
     i.setState(i.state);
   }
 
   handleMatrixUserIdChange(i: Settings, event: any) {
-    i.state.saveUserSettingsForm.matrix_user_id = event.target.value;
-    if (
-      i.state.saveUserSettingsForm.matrix_user_id == "" &&
-      !UserService.Instance.myUserInfo.local_user_view.person.matrix_user_id
-    ) {
-      i.state.saveUserSettingsForm.matrix_user_id = undefined;
-    }
+    i.state.saveUserSettingsForm.matrix_user_id = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -995,6 +1080,7 @@ export class Settings extends Component<any, SettingsState> {
   handleSaveSettingsSubmit(i: Settings, event: any) {
     event.preventDefault();
     i.state.saveUserSettingsLoading = true;
+    i.state.saveUserSettingsForm.auth = auth().unwrap();
     i.setState(i.state);
 
     WebSocketService.Instance.send(
@@ -1005,6 +1091,7 @@ export class Settings extends Component<any, SettingsState> {
   handleChangePasswordSubmit(i: Settings, event: any) {
     event.preventDefault();
     i.state.changePasswordLoading = true;
+    i.state.changePasswordForm.auth = auth().unwrap();
     i.setState(i.state);
 
     WebSocketService.Instance.send(
@@ -1023,14 +1110,10 @@ export class Settings extends Component<any, SettingsState> {
     i.setState(i.state);
   }
 
-  handleLogoutClick(i: Settings) {
-    UserService.Instance.logout();
-    i.context.router.history.push("/");
-  }
-
   handleDeleteAccount(i: Settings, event: any) {
     event.preventDefault();
     i.state.deleteAccountLoading = true;
+    i.state.deleteAccountForm.auth = auth().unwrap();
     i.setState(i.state);
 
     WebSocketService.Instance.send(
@@ -1048,53 +1131,77 @@ export class Settings extends Component<any, SettingsState> {
   }
 
   setUserInfo() {
-    let luv = UserService.Instance.myUserInfo.local_user_view;
-    this.state.saveUserSettingsForm.show_nsfw = luv.local_user.show_nsfw;
-    this.state.saveUserSettingsForm.theme = luv.local_user.theme
-      ? luv.local_user.theme
-      : "browser";
-    this.state.saveUserSettingsForm.default_sort_type =
-      luv.local_user.default_sort_type;
-    this.state.saveUserSettingsForm.default_listing_type =
-      luv.local_user.default_listing_type;
-    this.state.saveUserSettingsForm.lang = luv.local_user.lang;
-    this.state.saveUserSettingsForm.avatar = luv.person.avatar;
-    this.state.saveUserSettingsForm.banner = luv.person.banner;
-    this.state.saveUserSettingsForm.display_name = luv.person.display_name;
-    this.state.saveUserSettingsForm.show_avatars = luv.local_user.show_avatars;
-    this.state.saveUserSettingsForm.bot_account = luv.person.bot_account;
-    this.state.saveUserSettingsForm.show_bot_accounts =
-      luv.local_user.show_bot_accounts;
-    this.state.saveUserSettingsForm.show_scores = luv.local_user.show_scores;
-    this.state.saveUserSettingsForm.show_read_posts =
-      luv.local_user.show_read_posts;
-    this.state.saveUserSettingsForm.show_new_post_notifs =
-      luv.local_user.show_new_post_notifs;
-    this.state.saveUserSettingsForm.email = luv.local_user.email;
-    this.state.saveUserSettingsForm.bio = luv.person.bio;
-    this.state.saveUserSettingsForm.send_notifications_to_email =
-      luv.local_user.send_notifications_to_email;
-    this.state.saveUserSettingsForm.matrix_user_id = luv.person.matrix_user_id;
-    this.state.personBlocks = UserService.Instance.myUserInfo.person_blocks;
-    this.state.communityBlocks =
-      UserService.Instance.myUserInfo.community_blocks;
+    UserService.Instance.myUserInfo.match({
+      some: mui => {
+        let luv = mui.local_user_view;
+        this.state.saveUserSettingsForm.show_nsfw = Some(
+          luv.local_user.show_nsfw
+        );
+        this.state.saveUserSettingsForm.theme = Some(
+          luv.local_user.theme ? luv.local_user.theme : "browser"
+        );
+        this.state.saveUserSettingsForm.default_sort_type = Some(
+          luv.local_user.default_sort_type
+        );
+        this.state.saveUserSettingsForm.default_listing_type = Some(
+          luv.local_user.default_listing_type
+        );
+        this.state.saveUserSettingsForm.lang = Some(luv.local_user.lang);
+        this.state.saveUserSettingsForm.avatar = luv.person.avatar;
+        this.state.saveUserSettingsForm.banner = luv.person.banner;
+        this.state.saveUserSettingsForm.display_name = luv.person.display_name;
+        this.state.saveUserSettingsForm.show_avatars = Some(
+          luv.local_user.show_avatars
+        );
+        this.state.saveUserSettingsForm.bot_account = Some(
+          luv.person.bot_account
+        );
+        this.state.saveUserSettingsForm.show_bot_accounts = Some(
+          luv.local_user.show_bot_accounts
+        );
+        this.state.saveUserSettingsForm.show_scores = Some(
+          luv.local_user.show_scores
+        );
+        this.state.saveUserSettingsForm.show_read_posts = Some(
+          luv.local_user.show_read_posts
+        );
+        this.state.saveUserSettingsForm.show_new_post_notifs = Some(
+          luv.local_user.show_new_post_notifs
+        );
+        this.state.saveUserSettingsForm.email = luv.local_user.email;
+        this.state.saveUserSettingsForm.bio = luv.person.bio;
+        this.state.saveUserSettingsForm.send_notifications_to_email = Some(
+          luv.local_user.send_notifications_to_email
+        );
+        this.state.saveUserSettingsForm.matrix_user_id =
+          luv.person.matrix_user_id;
+        this.state.personBlocks = mui.person_blocks;
+        this.state.communityBlocks = mui.community_blocks;
+      },
+      none: void 0,
+    });
   }
 
   parseMessage(msg: any) {
     let op = wsUserOp(msg);
     console.log(msg);
     if (msg.error) {
+      this.setState({
+        saveUserSettingsLoading: false,
+        changePasswordLoading: false,
+        deleteAccountLoading: false,
+      });
       toast(i18n.t(msg.error), "danger");
       return;
     } else if (op == UserOperation.SaveUserSettings) {
-      let data = wsJsonToRes<LoginResponse>(msg).data;
+      let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
       UserService.Instance.login(data);
       this.state.saveUserSettingsLoading = false;
       this.setState(this.state);
-
+      toast(i18n.t("saved"));
       window.scrollTo(0, 0);
     } else if (op == UserOperation.ChangePassword) {
-      let data = wsJsonToRes<LoginResponse>(msg).data;
+      let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
       UserService.Instance.login(data);
       this.state.changePasswordLoading = false;
       this.setState(this.state);
@@ -1108,11 +1215,20 @@ export class Settings extends Component<any, SettingsState> {
       UserService.Instance.logout();
       window.location.href = "/";
     } else if (op == UserOperation.BlockPerson) {
-      let data = wsJsonToRes<BlockPersonResponse>(msg).data;
-      this.setState({ personBlocks: updatePersonBlock(data) });
+      let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
+      updatePersonBlock(data).match({
+        some: blocks => this.setState({ personBlocks: blocks }),
+        none: void 0,
+      });
     } else if (op == UserOperation.BlockCommunity) {
-      let data = wsJsonToRes<BlockCommunityResponse>(msg).data;
-      this.setState({ communityBlocks: updateCommunityBlock(data) });
+      let data = wsJsonToRes<BlockCommunityResponse>(
+        msg,
+        BlockCommunityResponse
+      );
+      updateCommunityBlock(data).match({
+        some: blocks => this.setState({ communityBlocks: blocks }),
+        none: void 0,
+      });
     }
   }
 }
diff --git a/src/shared/components/person/verify-email.tsx b/src/shared/components/person/verify-email.tsx
new file mode 100644 (file)
index 0000000..fed026f
--- /dev/null
@@ -0,0 +1,103 @@
+import { None } from "@sniptt/monads/build";
+import { Component } from "inferno";
+import {
+  GetSiteResponse,
+  UserOperation,
+  VerifyEmail as VerifyEmailForm,
+  VerifyEmailResponse,
+  wsJsonToRes,
+  wsUserOp,
+} from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
+import {
+  isBrowser,
+  setIsoData,
+  toast,
+  wsClient,
+  wsSubscribe,
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+
+interface State {
+  verifyEmailForm: VerifyEmailForm;
+  siteRes: GetSiteResponse;
+}
+
+export class VerifyEmail extends Component<any, State> {
+  private isoData = setIsoData(this.context);
+  private subscription: Subscription;
+
+  emptyState: State = {
+    verifyEmailForm: new VerifyEmailForm({
+      token: this.props.match.params.token,
+    }),
+    siteRes: this.isoData.site_res,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+
+    this.state = this.emptyState;
+
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+  }
+
+  componentDidMount() {
+    WebSocketService.Instance.send(
+      wsClient.verifyEmail(this.state.verifyEmailForm)
+    );
+  }
+
+  componentWillUnmount() {
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
+  }
+
+  get documentTitle(): string {
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("verify_email")} - ${siteView.site.name}`,
+      none: "",
+    });
+  }
+
+  render() {
+    return (
+      <div class="container">
+        <HtmlTags
+          title={this.documentTitle}
+          path={this.context.router.route.match.url}
+          description={None}
+          image={None}
+        />
+        <div class="row">
+          <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+            <h5>{i18n.t("verify_email")}</h5>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+  parseMessage(msg: any) {
+    let op = wsUserOp(msg);
+    console.log(msg);
+    if (msg.error) {
+      toast(i18n.t(msg.error), "danger");
+      this.setState(this.state);
+      this.props.history.push("/");
+      return;
+    } else if (op == UserOperation.VerifyEmail) {
+      let data = wsJsonToRes<VerifyEmailResponse>(msg, VerifyEmailResponse);
+      if (data) {
+        toast(i18n.t("email_verified"));
+        this.state = this.emptyState;
+        this.setState(this.state);
+        this.props.history.push("/login");
+      }
+    }
+  }
+}
index b5c95c4a85fb68f14609d0b0757fe8c2ab820a70..68d546e2e376f5009b81095d1bf0d33f82ef2787 100644 (file)
@@ -1,48 +1,50 @@
+import { Either, Left, None, Option, Right, Some } from "@sniptt/monads";
 import { Component } from "inferno";
 import {
-  CommunityView,
   GetCommunity,
   GetCommunityResponse,
+  GetSiteResponse,
   ListCommunities,
   ListCommunitiesResponse,
   ListingType,
   PostView,
-  SiteView,
   SortType,
+  toOption,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { InitialFetchRequest, PostFormParams } from "shared/interfaces";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
+  enableDownvotes,
+  enableNsfw,
   fetchLimit,
   isBrowser,
   setIsoData,
-  setOptionalAuth,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
 import { PostForm } from "./post-form";
 
 interface CreatePostState {
-  site_view: SiteView;
-  communities: CommunityView[];
+  listCommunitiesResponse: Option<ListCommunitiesResponse>;
+  siteRes: GetSiteResponse;
   loading: boolean;
 }
 
 export class CreatePost extends Component<any, CreatePostState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(this.context, ListCommunitiesResponse);
   private subscription: Subscription;
   private emptyState: CreatePostState = {
-    site_view: this.isoData.site_res.site_view,
-    communities: [],
+    siteRes: this.isoData.site_res,
+    listCommunitiesResponse: None,
     loading: true,
   };
 
@@ -51,7 +53,7 @@ export class CreatePost extends Component<any, CreatePostState> {
     this.handlePostCreate = this.handlePostCreate.bind(this);
     this.state = this.emptyState;
 
-    if (!UserService.Instance.myUserInfo && isBrowser()) {
+    if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
       toast(i18n.t("not_logged_in"), "danger");
       this.context.router.history.push(`/login`);
     }
@@ -61,7 +63,9 @@ export class CreatePost extends Component<any, CreatePostState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.communities = this.isoData.routeData[0].communities;
+      this.state.listCommunitiesResponse = Some(
+        this.isoData.routeData[0] as ListCommunitiesResponse
+      );
       this.state.loading = false;
     } else {
       this.refetch();
@@ -69,27 +73,39 @@ export class CreatePost extends Component<any, CreatePostState> {
   }
 
   refetch() {
-    if (this.params.community_id) {
-      let form: GetCommunity = {
-        id: this.params.community_id,
-      };
-      WebSocketService.Instance.send(wsClient.getCommunity(form));
-    } else if (this.params.community_name) {
-      let form: GetCommunity = {
-        name: this.params.community_name,
-      };
-      WebSocketService.Instance.send(wsClient.getCommunity(form));
-    } else {
-      let listCommunitiesForm: ListCommunities = {
-        type_: ListingType.All,
-        sort: SortType.TopAll,
-        limit: fetchLimit,
-        auth: authField(false),
-      };
-      WebSocketService.Instance.send(
-        wsClient.listCommunities(listCommunitiesForm)
-      );
-    }
+    this.params.nameOrId.match({
+      some: opt =>
+        opt.match({
+          left: name => {
+            let form = new GetCommunity({
+              name: Some(name),
+              id: None,
+              auth: auth(false).ok(),
+            });
+            WebSocketService.Instance.send(wsClient.getCommunity(form));
+          },
+          right: id => {
+            let form = new GetCommunity({
+              id: Some(id),
+              name: None,
+              auth: auth(false).ok(),
+            });
+            WebSocketService.Instance.send(wsClient.getCommunity(form));
+          },
+        }),
+      none: () => {
+        let listCommunitiesForm = new ListCommunities({
+          type_: Some(ListingType.All),
+          sort: Some(SortType.TopAll),
+          limit: Some(fetchLimit),
+          page: None,
+          auth: auth(false).ok(),
+        });
+        WebSocketService.Instance.send(
+          wsClient.listCommunities(listCommunitiesForm)
+        );
+      },
+    });
   }
 
   componentWillUnmount() {
@@ -99,7 +115,10 @@ export class CreatePost extends Component<any, CreatePostState> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("create_post")} - ${this.state.site_view.site.name}`;
+    return this.state.siteRes.site_view.match({
+      some: siteView => `${i18n.t("create_post")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
@@ -108,24 +127,32 @@ export class CreatePost extends Component<any, CreatePostState> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         {this.state.loading ? (
           <h5>
             <Spinner large />
           </h5>
         ) : (
-          <div class="row">
-            <div class="col-12 col-lg-6 offset-lg-3 mb-4">
-              <h5>{i18n.t("create_post")}</h5>
-              <PostForm
-                communities={this.state.communities}
-                onCreate={this.handlePostCreate}
-                params={this.params}
-                enableDownvotes={this.state.site_view.site.enable_downvotes}
-                enableNsfw={this.state.site_view.site.enable_nsfw}
-              />
-            </div>
-          </div>
+          this.state.listCommunitiesResponse.match({
+            some: res => (
+              <div class="row">
+                <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+                  <h5>{i18n.t("create_post")}</h5>
+                  <PostForm
+                    post_view={None}
+                    communities={Some(res.communities)}
+                    onCreate={this.handlePostCreate}
+                    params={Some(this.params)}
+                    enableDownvotes={enableDownvotes(this.state.siteRes)}
+                    enableNsfw={enableNsfw(this.state.siteRes)}
+                  />
+                </div>
+              </div>
+            ),
+            none: <></>,
+          })
         )}
       </div>
     );
@@ -133,36 +160,48 @@ export class CreatePost extends Component<any, CreatePostState> {
 
   get params(): PostFormParams {
     let urlParams = new URLSearchParams(this.props.location.search);
+    let name = toOption(urlParams.get("community_name")).or(
+      this.prevCommunityName
+    );
+    let id = toOption(urlParams.get("community_id"))
+      .map(Number)
+      .or(this.prevCommunityId);
+    let nameOrId: Option<Either<string, number>>;
+    if (name.isSome()) {
+      nameOrId = Some(Left(name.unwrap()));
+    } else if (id.isSome()) {
+      nameOrId = Some(Right(id.unwrap()));
+    } else {
+      nameOrId = None;
+    }
+
     let params: PostFormParams = {
-      name: urlParams.get("title"),
-      community_name: urlParams.get("community_name") || this.prevCommunityName,
-      community_id: urlParams.get("community_id")
-        ? Number(urlParams.get("community_id")) || this.prevCommunityId
-        : null,
-      body: urlParams.get("body"),
-      url: urlParams.get("url"),
+      name: toOption(urlParams.get("title")),
+      nameOrId,
+      body: toOption(urlParams.get("body")),
+      url: toOption(urlParams.get("url")),
     };
 
     return params;
   }
 
-  get prevCommunityName(): string {
+  get prevCommunityName(): Option<string> {
     if (this.props.match.params.name) {
-      return this.props.match.params.name;
+      return toOption(this.props.match.params.name);
     } else if (this.props.location.state) {
       let lastLocation = this.props.location.state.prevPath;
       if (lastLocation.includes("/c/")) {
-        return lastLocation.split("/c/")[1];
+        return toOption(lastLocation.split("/c/")[1]);
       }
     }
-    return null;
+    return None;
   }
 
-  get prevCommunityId(): number {
+  get prevCommunityId(): Option<number> {
     if (this.props.match.params.id) {
-      return this.props.match.params.id;
+      return toOption(this.props.match.params.id);
     }
-    return null;
+    return None;
   }
 
   handlePostCreate(post_view: PostView) {
@@ -170,12 +209,13 @@ export class CreatePost extends Component<any, CreatePostState> {
   }
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
-    let listCommunitiesForm: ListCommunities = {
-      type_: ListingType.All,
-      sort: SortType.TopAll,
-      limit: fetchLimit,
-    };
-    setOptionalAuth(listCommunitiesForm, req.auth);
+    let listCommunitiesForm = new ListCommunities({
+      type_: Some(ListingType.All),
+      sort: Some(SortType.TopAll),
+      limit: Some(fetchLimit),
+      page: None,
+      auth: req.auth,
+    });
     return [req.client.listCommunities(listCommunitiesForm)];
   }
 
@@ -186,13 +226,18 @@ export class CreatePost extends Component<any, CreatePostState> {
       toast(i18n.t(msg.error), "danger");
       return;
     } else if (op == UserOperation.ListCommunities) {
-      let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
-      this.state.communities = data.communities;
+      let data = wsJsonToRes<ListCommunitiesResponse>(
+        msg,
+        ListCommunitiesResponse
+      );
+      this.state.listCommunitiesResponse = Some(data);
       this.state.loading = false;
       this.setState(this.state);
     } else if (op == UserOperation.GetCommunity) {
-      let data = wsJsonToRes<GetCommunityResponse>(msg).data;
-      this.state.communities = [data.community_view];
+      let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
+      this.state.listCommunitiesResponse = Some({
+        communities: [data.community_view],
+      });
       this.state.loading = false;
       this.setState(this.state);
     }
index 85fcdb672556f07e91c611de3ad2d28845c49e0c..116cdc9a4ea3ba281f8a43afda09f2dbebeaec55 100644 (file)
@@ -1,6 +1,7 @@
 import { Component, linkEvent } from "inferno";
 import { Post } from "lemmy-js-client";
 import { i18n } from "../../i18next";
+import { relTags } from "../../utils";
 import { Icon } from "../common/icon";
 
 interface MetadataCardProps {
@@ -28,56 +29,71 @@ export class MetadataCard extends Component<
     let post = this.props.post;
     return (
       <>
-        {post.embed_title && !this.state.expanded && (
-          <div class="card border-secondary mt-3 mb-2">
-            <div class="row">
-              <div class="col-12">
-                <div class="card-body">
-                  {post.name !== post.embed_title && [
-                    <h5 class="card-title d-inline">
-                      <a class="text-body" href={post.url} rel="noopener">
-                        {post.embed_title}
-                      </a>
-                    </h5>,
-                    <span class="d-inline-block ml-2 mb-2 small text-muted">
-                      <a
-                        class="text-muted font-italic"
-                        href={post.url}
-                        rel="noopener"
-                      >
-                        {new URL(post.url).hostname}
-                        <Icon icon="external-link" classes="ml-1" />
-                      </a>
-                    </span>,
-                  ]}
-                  {post.embed_description && (
-                    <div
-                      className="card-text small text-muted md-div"
-                      dangerouslySetInnerHTML={{
-                        __html: post.embed_description,
-                      }}
-                    />
-                  )}
-                  {post.embed_html && (
-                    <button
-                      class="mt-2 btn btn-secondary text-monospace"
-                      onClick={linkEvent(this, this.handleIframeExpand)}
-                      data-tippy-content={i18n.t("expand_here")}
-                    >
-                      {this.state.expanded ? "-" : "+"}
-                    </button>
-                  )}
-                </div>
-              </div>
-            </div>
-          </div>
-        )}
-        {this.state.expanded && (
-          <div
-            class="mt-3 mb-2"
-            dangerouslySetInnerHTML={{ __html: post.embed_html }}
-          />
-        )}
+        {!this.state.expanded &&
+          post.embed_title.match({
+            some: embedTitle =>
+              post.url.match({
+                some: url => (
+                  <div class="card border-secondary mt-3 mb-2">
+                    <div class="row">
+                      <div class="col-12">
+                        <div class="card-body">
+                          {post.name !== embedTitle && [
+                            <h5 class="card-title d-inline">
+                              <a class="text-body" href={url} rel={relTags}>
+                                {embedTitle}
+                              </a>
+                            </h5>,
+                            <span class="d-inline-block ml-2 mb-2 small text-muted">
+                              <a
+                                class="text-muted font-italic"
+                                href={url}
+                                rel={relTags}
+                              >
+                                {new URL(url).hostname}
+                                <Icon icon="external-link" classes="ml-1" />
+                              </a>
+                            </span>,
+                          ]}
+                          {post.embed_description.match({
+                            some: desc => (
+                              <div
+                                className="card-text small text-muted md-div"
+                                dangerouslySetInnerHTML={{
+                                  __html: desc,
+                                }}
+                              />
+                            ),
+                            none: <></>,
+                          })}
+                          {post.embed_html.isSome() && (
+                            <button
+                              class="mt-2 btn btn-secondary text-monospace"
+                              onClick={linkEvent(this, this.handleIframeExpand)}
+                              data-tippy-content={i18n.t("expand_here")}
+                            >
+                              {this.state.expanded ? "-" : "+"}
+                            </button>
+                          )}
+                        </div>
+                      </div>
+                    </div>
+                  </div>
+                ),
+                none: <></>,
+              }),
+            none: <></>,
+          })}
+        {this.state.expanded &&
+          post.embed_html.match({
+            some: html => (
+              <div
+                class="mt-3 mb-2"
+                dangerouslySetInnerHTML={{ __html: html }}
+              />
+            ),
+            none: <></>,
+          })}
       </>
     );
   }
index 10309fbb26cfe0ee23c9de0e11fcf6b74264c8a3..dde1cb4237d88ce60eb0eefadb49e592b80e4d4b 100644 (file)
@@ -1,3 +1,4 @@
+import { None, Option, Some } from "@sniptt/monads";
 import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
@@ -12,7 +13,10 @@ import {
   SearchResponse,
   SearchType,
   SortType,
+  toUndefined,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { pictrsUri } from "../../env";
@@ -20,8 +24,8 @@ import { i18n } from "../../i18next";
 import { PostFormParams } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  archiveUrl,
-  authField,
+  archiveTodayUrl,
+  auth,
   capitalizeFirstLetter,
   choicesConfig,
   communitySelectName,
@@ -29,17 +33,19 @@ import {
   debounce,
   fetchCommunities,
   getSiteMetadata,
+  ghostArchiveUrl,
   isBrowser,
   isImage,
   pictrsDeleteToast,
+  relTags,
   setupTippy,
   toast,
+  trendingFetchLimit,
   validTitle,
   validURL,
+  webArchiveUrl,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { Icon, Spinner } from "../common/icon";
 import { MarkdownTextArea } from "../common/markdown-textarea";
@@ -53,42 +59,45 @@ if (isBrowser()) {
 const MAX_POST_TITLE_LENGTH = 200;
 
 interface PostFormProps {
-  post_view?: PostView; // If a post is given, that means this is an edit
-  communities?: CommunityView[];
-  params?: PostFormParams;
+  post_view: Option<PostView>; // If a post is given, that means this is an edit
+  communities: Option<CommunityView[]>;
+  params: Option<PostFormParams>;
   onCancel?(): any;
   onCreate?(post: PostView): any;
   onEdit?(post: PostView): any;
-  enableNsfw: boolean;
-  enableDownvotes: boolean;
+  enableNsfw?: boolean;
+  enableDownvotes?: boolean;
 }
 
 interface PostFormState {
   postForm: CreatePost;
+  suggestedTitle: Option<string>;
+  suggestedPosts: Option<PostView[]>;
+  crossPosts: Option<PostView[]>;
   loading: boolean;
   imageLoading: boolean;
   previewMode: boolean;
-  suggestedTitle: string;
-  suggestedPosts: PostView[];
-  crossPosts: PostView[];
 }
 
 export class PostForm extends Component<PostFormProps, PostFormState> {
   private subscription: Subscription;
   private choices: any;
   private emptyState: PostFormState = {
-    postForm: {
-      community_id: null,
-      name: null,
-      nsfw: false,
-      auth: authField(false),
-    },
+    postForm: new CreatePost({
+      community_id: undefined,
+      name: undefined,
+      nsfw: Some(false),
+      url: None,
+      body: None,
+      honeypot: None,
+      auth: undefined,
+    }),
     loading: false,
     imageLoading: false,
     previewMode: false,
-    suggestedTitle: undefined,
-    suggestedPosts: [],
-    crossPosts: [],
+    suggestedTitle: None,
+    suggestedPosts: None,
+    crossPosts: None,
   };
 
   constructor(props: any, context: any) {
@@ -100,26 +109,28 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
     this.state = this.emptyState;
 
     // Means its an edit
-    if (this.props.post_view) {
-      this.state.postForm = {
-        body: this.props.post_view.post.body,
-        name: this.props.post_view.post.name,
-        community_id: this.props.post_view.community.id,
-        url: this.props.post_view.post.url,
-        nsfw: this.props.post_view.post.nsfw,
-        auth: authField(),
-      };
-    }
-
-    if (this.props.params) {
-      this.state.postForm.name = this.props.params.name;
-      if (this.props.params.url) {
-        this.state.postForm.url = this.props.params.url;
-      }
-      if (this.props.params.body) {
-        this.state.postForm.body = this.props.params.body;
-      }
-    }
+    this.props.post_view.match({
+      some: pv =>
+        (this.state.postForm = new CreatePost({
+          body: pv.post.body,
+          name: pv.post.name,
+          community_id: pv.community.id,
+          url: pv.post.url,
+          nsfw: Some(pv.post.nsfw),
+          honeypot: None,
+          auth: auth().unwrap(),
+        })),
+      none: void 0,
+    });
+
+    this.props.params.match({
+      some: params => {
+        this.state.postForm.name = toUndefined(params.name);
+        this.state.postForm.url = params.url;
+        this.state.postForm.body = params.body;
+      },
+      none: void 0,
+    });
 
     this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
@@ -138,8 +149,8 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
     if (
       !this.state.loading &&
       (this.state.postForm.name ||
-        this.state.postForm.url ||
-        this.state.postForm.body)
+        this.state.postForm.url.isSome() ||
+        this.state.postForm.body.isSome())
     ) {
       window.onbeforeunload = () => true;
     } else {
@@ -160,8 +171,8 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
           when={
             !this.state.loading &&
             (this.state.postForm.name ||
-              this.state.postForm.url ||
-              this.state.postForm.body)
+              this.state.postForm.url.isSome() ||
+              this.state.postForm.body.isSome())
           }
           message={i18n.t("block_leaving")}
         />
@@ -175,26 +186,27 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
                 type="url"
                 id="post-url"
                 class="form-control"
-                value={this.state.postForm.url}
+                value={toUndefined(this.state.postForm.url)}
                 onInput={linkEvent(this, this.handlePostUrlChange)}
                 onPaste={linkEvent(this, this.handleImageUploadPaste)}
               />
-              {this.state.suggestedTitle && (
-                <div
-                  class="mt-1 text-muted small font-weight-bold pointer"
-                  role="button"
-                  onClick={linkEvent(this, this.copySuggestedTitle)}
-                >
-                  {i18n.t("copy_suggested_title", {
-                    title: this.state.suggestedTitle,
-                  })}
-                </div>
-              )}
+              {this.state.suggestedTitle.match({
+                some: title => (
+                  <div
+                    class="mt-1 text-muted small font-weight-bold pointer"
+                    role="button"
+                    onClick={linkEvent(this, this.copySuggestedTitle)}
+                  >
+                    {i18n.t("copy_suggested_title", { title: "" })} {title}
+                  </div>
+                ),
+                none: <></>,
+              })}
               <form>
                 <label
                   htmlFor="file-upload"
                   className={`${
-                    UserService.Instance.myUserInfo && "pointer"
+                    UserService.Instance.myUserInfo.isSome() && "pointer"
                   } d-inline-block float-right text-muted font-weight-bold`}
                   data-tippy-content={i18n.t("upload_image")}
                 >
@@ -206,38 +218,68 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
                   accept="image/*,video/*"
                   name="file"
                   class="d-none"
-                  disabled={!UserService.Instance.myUserInfo}
+                  disabled={UserService.Instance.myUserInfo.isNone()}
                   onChange={linkEvent(this, this.handleImageUpload)}
                 />
               </form>
-              {this.state.postForm.url && validURL(this.state.postForm.url) && (
-                <a
-                  href={`${archiveUrl}/?run=1&url=${encodeURIComponent(
-                    this.state.postForm.url
-                  )}`}
-                  class="mr-2 d-inline-block float-right text-muted small font-weight-bold"
-                  rel="noopener"
-                >
-                  {i18n.t("archive_link")}
-                </a>
-              )}
+              {this.state.postForm.url.match({
+                some: url =>
+                  validURL(url) && (
+                    <div>
+                      <a
+                        href={`${webArchiveUrl}/save/${encodeURIComponent(
+                          url
+                        )}`}
+                        class="mr-2 d-inline-block float-right text-muted small font-weight-bold"
+                        rel={relTags}
+                      >
+                        archive.org {i18n.t("archive_link")}
+                      </a>
+                      <a
+                        href={`${ghostArchiveUrl}/search?term=${encodeURIComponent(
+                          url
+                        )}`}
+                        class="mr-2 d-inline-block float-right text-muted small font-weight-bold"
+                        rel={relTags}
+                      >
+                        ghostarchive.org {i18n.t("archive_link")}
+                      </a>
+                      <a
+                        href={`${archiveTodayUrl}/?run=1&url=${encodeURIComponent(
+                          url
+                        )}`}
+                        class="mr-2 d-inline-block float-right text-muted small font-weight-bold"
+                        rel={relTags}
+                      >
+                        archive.today {i18n.t("archive_link")}
+                      </a>
+                    </div>
+                  ),
+                none: <></>,
+              })}
               {this.state.imageLoading && <Spinner />}
-              {isImage(this.state.postForm.url) && (
-                <img src={this.state.postForm.url} class="img-fluid" alt="" />
-              )}
-              {this.state.crossPosts.length > 0 && (
-                <>
-                  <div class="my-1 text-muted small font-weight-bold">
-                    {i18n.t("cross_posts")}
-                  </div>
-                  <PostListings
-                    showCommunity
-                    posts={this.state.crossPosts}
-                    enableDownvotes={this.props.enableDownvotes}
-                    enableNsfw={this.props.enableNsfw}
-                  />
-                </>
-              )}
+              {this.state.postForm.url.match({
+                some: url =>
+                  isImage(url) && <img src={url} class="img-fluid" alt="" />,
+                none: <></>,
+              })}
+              {this.state.crossPosts.match({
+                some: xPosts =>
+                  xPosts.length > 0 && (
+                    <>
+                      <div class="my-1 text-muted small font-weight-bold">
+                        {i18n.t("cross_posts")}
+                      </div>
+                      <PostListings
+                        showCommunity
+                        posts={xPosts}
+                        enableDownvotes={this.props.enableDownvotes}
+                        enableNsfw={this.props.enableNsfw}
+                      />
+                    </>
+                  ),
+                none: <></>,
+              })}
             </div>
           </div>
           <div class="form-group row">
@@ -262,18 +304,23 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
                   {i18n.t("invalid_post_title")}
                 </div>
               )}
-              {this.state.suggestedPosts.length > 0 && (
-                <>
-                  <div class="my-1 text-muted small font-weight-bold">
-                    {i18n.t("related_posts")}
-                  </div>
-                  <PostListings
-                    posts={this.state.suggestedPosts}
-                    enableDownvotes={this.props.enableDownvotes}
-                    enableNsfw={this.props.enableNsfw}
-                  />
-                </>
-              )}
+              {this.state.suggestedPosts.match({
+                some: sPosts =>
+                  sPosts.length > 0 && (
+                    <>
+                      <div class="my-1 text-muted small font-weight-bold">
+                        {i18n.t("related_posts")}
+                      </div>
+                      <PostListings
+                        showCommunity
+                        posts={sPosts}
+                        enableDownvotes={this.props.enableDownvotes}
+                        enableNsfw={this.props.enableNsfw}
+                      />
+                    </>
+                  ),
+                none: <></>,
+              })}
             </div>
           </div>
 
@@ -283,10 +330,13 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
               <MarkdownTextArea
                 initialContent={this.state.postForm.body}
                 onContentChange={this.handlePostBodyChange}
+                placeholder={None}
+                buttonTitle={None}
+                maxLength={None}
               />
             </div>
           </div>
-          {!this.props.post_view && (
+          {this.props.post_view.isNone() && (
             <div class="form-group row">
               <label class="col-sm-2 col-form-label" htmlFor="post-community">
                 {i18n.t("community")}
@@ -299,7 +349,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
                   onInput={linkEvent(this, this.handlePostCommunityChange)}
                 >
                   <option>{i18n.t("select_a_community")}</option>
-                  {this.props.communities.map(cv => (
+                  {this.props.communities.unwrapOr([]).map(cv => (
                     <option value={cv.community.id}>
                       {communitySelectName(cv)}
                     </option>
@@ -310,22 +360,32 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
           )}
           {this.props.enableNsfw && (
             <div class="form-group row">
+              <legend class="col-form-label col-sm-2 pt-0">
+                {i18n.t("nsfw")}
+              </legend>
               <div class="col-sm-10">
                 <div class="form-check">
                   <input
-                    class="form-check-input"
+                    class="form-check-input position-static"
                     id="post-nsfw"
                     type="checkbox"
-                    checked={this.state.postForm.nsfw}
+                    checked={toUndefined(this.state.postForm.nsfw)}
                     onChange={linkEvent(this, this.handlePostNsfwChange)}
                   />
-                  <label class="form-check-label" htmlFor="post-nsfw">
-                    {i18n.t("nsfw")}
-                  </label>
                 </div>
               </div>
             </div>
           )}
+          <input
+            tabIndex={-1}
+            autoComplete="false"
+            name="a_password"
+            type="text"
+            class="form-control honeypot"
+            id="register-honey"
+            value={toUndefined(this.state.postForm.honeypot)}
+            onInput={linkEvent(this, this.handleHoneyPotChange)}
+          />
           <div class="form-group row">
             <div class="col-sm-10">
               <button
@@ -337,13 +397,13 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
               >
                 {this.state.loading ? (
                   <Spinner />
-                ) : this.props.post_view ? (
+                ) : this.props.post_view.isSome() ? (
                   capitalizeFirstLetter(i18n.t("save"))
                 ) : (
                   capitalizeFirstLetter(i18n.t("create"))
                 )}
               </button>
-              {this.props.post_view && (
+              {this.props.post_view.isSome() && (
                 <button
                   type="button"
                   class="btn btn-secondary"
@@ -363,65 +423,87 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
     event.preventDefault();
 
     // Coerce empty url string to undefined
-    if (i.state.postForm.url !== undefined && i.state.postForm.url === "") {
-      i.state.postForm.url = undefined;
+    if (
+      i.state.postForm.url.isSome() &&
+      i.state.postForm.url.unwrapOr("blank") === ""
+    ) {
+      i.state.postForm.url = None;
     }
 
-    if (i.props.post_view) {
-      let form: EditPost = {
-        ...i.state.postForm,
-        post_id: i.props.post_view.post.id,
-      };
-      WebSocketService.Instance.send(wsClient.editPost(form));
-    } else {
-      WebSocketService.Instance.send(wsClient.createPost(i.state.postForm));
-    }
+    let pForm = i.state.postForm;
+    i.props.post_view.match({
+      some: pv => {
+        let form = new EditPost({
+          name: Some(pForm.name),
+          url: pForm.url,
+          body: pForm.body,
+          nsfw: pForm.nsfw,
+          post_id: pv.post.id,
+          auth: auth().unwrap(),
+        });
+        WebSocketService.Instance.send(wsClient.editPost(form));
+      },
+      none: () => {
+        i.state.postForm.auth = auth().unwrap();
+        WebSocketService.Instance.send(wsClient.createPost(i.state.postForm));
+      },
+    });
     i.state.loading = true;
     i.setState(i.state);
   }
 
   copySuggestedTitle(i: PostForm) {
-    i.state.postForm.name = i.state.suggestedTitle.substring(
-      0,
-      MAX_POST_TITLE_LENGTH
-    );
-    i.state.suggestedTitle = undefined;
-    setTimeout(() => {
-      let textarea: any = document.getElementById("post-title");
-      autosize.update(textarea);
-    }, 10);
-    i.setState(i.state);
+    i.state.suggestedTitle.match({
+      some: sTitle => {
+        i.state.postForm.name = sTitle.substring(0, MAX_POST_TITLE_LENGTH);
+        i.state.suggestedTitle = None;
+        setTimeout(() => {
+          let textarea: any = document.getElementById("post-title");
+          autosize.update(textarea);
+        }, 10);
+        i.setState(i.state);
+      },
+      none: void 0,
+    });
   }
 
   handlePostUrlChange(i: PostForm, event: any) {
-    i.state.postForm.url = event.target.value;
+    i.state.postForm.url = Some(event.target.value);
     i.setState(i.state);
     i.fetchPageTitle();
   }
 
   fetchPageTitle() {
-    if (validURL(this.state.postForm.url)) {
-      let form: Search = {
-        q: this.state.postForm.url,
-        type_: SearchType.Url,
-        sort: SortType.TopAll,
-        listing_type: ListingType.All,
-        page: 1,
-        limit: 6,
-        auth: authField(false),
-      };
-
-      WebSocketService.Instance.send(wsClient.search(form));
-
-      // Fetch the page title
-      getSiteMetadata(this.state.postForm.url).then(d => {
-        this.state.suggestedTitle = d.metadata.title;
-        this.setState(this.state);
-      });
-    } else {
-      this.state.suggestedTitle = undefined;
-      this.state.crossPosts = [];
-    }
+    this.state.postForm.url.match({
+      some: url => {
+        if (validURL(url)) {
+          let form = new Search({
+            q: url,
+            community_id: None,
+            community_name: None,
+            creator_id: None,
+            type_: Some(SearchType.Url),
+            sort: Some(SortType.TopAll),
+            listing_type: Some(ListingType.All),
+            page: Some(1),
+            limit: Some(trendingFetchLimit),
+            auth: auth(false).ok(),
+          });
+
+          WebSocketService.Instance.send(wsClient.search(form));
+
+          // Fetch the page title
+          getSiteMetadata(url).then(d => {
+            this.state.suggestedTitle = d.metadata.title;
+            this.setState(this.state);
+          });
+        } else {
+          this.state.suggestedTitle = None;
+          this.state.crossPosts = None;
+        }
+      },
+      none: void 0,
+    });
   }
 
   handlePostNameChange(i: PostForm, event: any) {
@@ -431,28 +513,30 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
   }
 
   fetchSimilarPosts() {
-    let form: Search = {
+    let form = new Search({
       q: this.state.postForm.name,
-      type_: SearchType.Posts,
-      sort: SortType.TopAll,
-      listing_type: ListingType.All,
-      community_id: this.state.postForm.community_id,
-      page: 1,
-      limit: 6,
-      auth: authField(false),
-    };
+      type_: Some(SearchType.Posts),
+      sort: Some(SortType.TopAll),
+      listing_type: Some(ListingType.All),
+      community_id: Some(this.state.postForm.community_id),
+      community_name: None,
+      creator_id: None,
+      page: Some(1),
+      limit: Some(trendingFetchLimit),
+      auth: auth(false).ok(),
+    });
 
     if (this.state.postForm.name !== "") {
       WebSocketService.Instance.send(wsClient.search(form));
     } else {
-      this.state.suggestedPosts = [];
+      this.state.suggestedPosts = None;
     }
 
     this.setState(this.state);
   }
 
   handlePostBodyChange(val: string) {
-    this.state.postForm.body = val;
+    this.state.postForm.body = Some(val);
     this.setState(this.state);
   }
 
@@ -462,7 +546,12 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
   }
 
   handlePostNsfwChange(i: PostForm, event: any) {
-    i.state.postForm.nsfw = event.target.checked;
+    i.state.postForm.nsfw = Some(event.target.checked);
+    i.setState(i.state);
+  }
+
+  handleHoneyPotChange(i: PostForm, event: any) {
+    i.state.postForm.honeypot = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -511,7 +600,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
           let url = `${pictrsUri}/${hash}`;
           let deleteToken = res.files[0].delete_token;
           let deleteUrl = `${pictrsUri}/delete/${deleteToken}/${hash}`;
-          i.state.postForm.url = url;
+          i.state.postForm.url = Some(url);
           i.state.imageLoading = false;
           i.setState(i.state);
           pictrsDeleteToast(
@@ -528,6 +617,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
       .catch(error => {
         i.state.imageLoading = false;
         i.setState(i.state);
+        console.error(error);
         toast(error, "danger");
       });
   }
@@ -549,79 +639,92 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
         this.choices.passedElement.element.addEventListener(
           "search",
           debounce(async (e: any) => {
-            let communities = (await fetchCommunities(e.detail.value))
-              .communities;
-            this.choices.setChoices(
-              communities.map(cv => communityToChoice(cv)),
-              "value",
-              "label",
-              true
-            );
-          }, 400),
+            try {
+              let communities = (await fetchCommunities(e.detail.value))
+                .communities;
+              this.choices.setChoices(
+                communities.map(cv => communityToChoice(cv)),
+                "value",
+                "label",
+                true
+              );
+            } catch (err) {
+              console.log(err);
+            }
+          }),
           false
         );
       }
     }
 
-    if (this.props.post_view) {
-      this.state.postForm.community_id = this.props.post_view.community.id;
-    } else if (
-      this.props.params &&
-      (this.props.params.community_id || this.props.params.community_name)
-    ) {
-      if (this.props.params.community_name) {
-        let foundCommunityId = this.props.communities.find(
-          r => r.community.name == this.props.params.community_name
-        ).community.id;
-        this.state.postForm.community_id = foundCommunityId;
-      } else if (this.props.params.community_id) {
-        this.state.postForm.community_id = this.props.params.community_id;
-      }
-
-      if (isBrowser()) {
-        this.choices.setChoiceByValue(
-          this.state.postForm.community_id.toString()
-        );
-      }
-      this.setState(this.state);
-    } else {
-      // By default, the null valued 'Select a Community'
+    this.props.post_view.match({
+      some: pv => (this.state.postForm.community_id = pv.community.id),
+      none: void 0,
+    });
+    this.props.params.match({
+      some: params =>
+        params.nameOrId.match({
+          some: nameOrId =>
+            nameOrId.match({
+              left: name => {
+                let foundCommunityId = this.props.communities
+                  .unwrapOr([])
+                  .find(r => r.community.name == name).community.id;
+                this.state.postForm.community_id = foundCommunityId;
+              },
+              right: id => (this.state.postForm.community_id = id),
+            }),
+          none: void 0,
+        }),
+      none: void 0,
+    });
+
+    if (isBrowser() && this.state.postForm.community_id) {
+      this.choices.setChoiceByValue(
+        this.state.postForm.community_id.toString()
+      );
     }
+    this.setState(this.state);
   }
 
   parseMessage(msg: any) {
     let op = wsUserOp(msg);
     console.log(msg);
     if (msg.error) {
-      toast(i18n.t(msg.error), "danger");
+      // Errors handled by top level pages
+      // toast(i18n.t(msg.error), "danger");
       this.state.loading = false;
       this.setState(this.state);
       return;
     } else if (op == UserOperation.CreatePost) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      if (
-        data.post_view.creator.id ==
-        UserService.Instance.myUserInfo.local_user_view.person.id
-      ) {
-        this.state.loading = false;
-        this.props.onCreate(data.post_view);
-      }
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          if (data.post_view.creator.id == mui.local_user_view.person.id) {
+            this.state.loading = false;
+            this.props.onCreate(data.post_view);
+          }
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.EditPost) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      if (
-        data.post_view.creator.id ==
-        UserService.Instance.myUserInfo.local_user_view.person.id
-      ) {
-        this.state.loading = false;
-        this.props.onEdit(data.post_view);
-      }
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      UserService.Instance.myUserInfo.match({
+        some: mui => {
+          if (data.post_view.creator.id == mui.local_user_view.person.id) {
+            this.state.loading = false;
+            this.props.onEdit(data.post_view);
+          }
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.Search) {
-      let data = wsJsonToRes<SearchResponse>(msg).data;
+      let data = wsJsonToRes<SearchResponse>(msg, SearchResponse);
 
       if (data.type_ == SearchType[SearchType.Posts]) {
-        this.state.suggestedPosts = data.posts;
+        this.state.suggestedPosts = Some(data.posts);
       } else if (data.type_ == SearchType[SearchType.Url]) {
-        this.state.crossPosts = data.posts;
+        this.state.crossPosts = Some(data.posts);
       }
       this.setState(this.state);
     }
index 9c6da3765acf58ca4e8e7f766d85c2f5a16f5160..672d3d6925d28a13d245c29eeaaaf158dcdd1994 100644 (file)
@@ -1,3 +1,5 @@
+import { None, Option, Some } from "@sniptt/monads";
+import classNames from "classnames";
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
@@ -8,36 +10,44 @@ import {
   BlockPerson,
   CommunityModeratorView,
   CreatePostLike,
+  CreatePostReport,
   DeletePost,
   LockPost,
   PersonViewSafe,
   PostView,
+  PurgePerson,
+  PurgePost,
   RemovePost,
   SavePost,
   StickyPost,
+  toUndefined,
   TransferCommunity,
-  TransferSite,
 } from "lemmy-js-client";
 import { externalHost } from "../../env";
 import { i18n } from "../../i18next";
-import { BanType } from "../../interfaces";
+import { BanType, PurgeType } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  amCommunityCreator,
+  auth,
+  canAdmin,
   canMod,
-  getUnixTime,
+  futureDaysToUnixTime,
   hostname,
+  isAdmin,
+  isBanned,
   isImage,
   isMod,
   isVideo,
   md,
   mdToHtml,
-  previewLines,
+  numToSI,
+  relTags,
   setupTippy,
   showScores,
   wsClient,
 } from "../../utils";
-import { Icon } from "../common/icon";
+import { Icon, PurgeWarning, Spinner } from "../common/icon";
 import { MomentTime } from "../common/moment-time";
 import { PictrsImage } from "../common/pictrs-image";
 import { CommunityLink } from "../community/community-link";
@@ -48,12 +58,16 @@ import { PostForm } from "./post-form";
 interface PostListingState {
   showEdit: boolean;
   showRemoveDialog: boolean;
-  removeReason: string;
+  showPurgeDialog: boolean;
+  purgeReason: Option<string>;
+  purgeType: PurgeType;
+  purgeLoading: boolean;
+  removeReason: Option<string>;
   showBanDialog: boolean;
-  removeData: boolean;
-  banReason: string;
-  banExpires: string;
+  banReason: Option<string>;
+  banExpireDays: Option<number>;
   banType: BanType;
+  removeData: boolean;
   showConfirmTransferSite: boolean;
   showConfirmTransferCommunity: boolean;
   imageExpanded: boolean;
@@ -61,7 +75,9 @@ interface PostListingState {
   showAdvanced: boolean;
   showMoreMobile: boolean;
   showBody: boolean;
-  my_vote: number;
+  showReportDialog: boolean;
+  reportReason: Option<string>;
+  my_vote: Option<number>;
   score: number;
   upvotes: number;
   downvotes: number;
@@ -69,25 +85,30 @@ interface PostListingState {
 
 interface PostListingProps {
   post_view: PostView;
-  duplicates?: PostView[];
+  duplicates: Option<PostView[]>;
+  moderators: Option<CommunityModeratorView[]>;
+  admins: Option<PersonViewSafe[]>;
   showCommunity?: boolean;
   showBody?: boolean;
-  moderators?: CommunityModeratorView[];
-  admins?: PersonViewSafe[];
-  enableDownvotes: boolean;
-  enableNsfw: boolean;
+  enableDownvotes?: boolean;
+  enableNsfw?: boolean;
+  viewOnly?: boolean;
 }
 
 export class PostListing extends Component<PostListingProps, PostListingState> {
   private emptyState: PostListingState = {
     showEdit: false,
     showRemoveDialog: false,
-    removeReason: null,
+    showPurgeDialog: false,
+    purgeReason: None,
+    purgeType: PurgeType.Person,
+    purgeLoading: false,
+    removeReason: None,
     showBanDialog: false,
-    removeData: false,
-    banReason: null,
-    banExpires: null,
+    banReason: None,
+    banExpireDays: None,
     banType: BanType.Community,
+    removeData: false,
     showConfirmTransferSite: false,
     showConfirmTransferCommunity: false,
     imageExpanded: false,
@@ -95,6 +116,8 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     showAdvanced: false,
     showMoreMobile: false,
     showBody: false,
+    showReportDialog: false,
+    reportReason: None,
     my_vote: this.props.post_view.my_vote,
     score: this.props.post_view.counts.score,
     upvotes: this.props.post_view.counts.upvotes,
@@ -123,17 +146,24 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   render() {
+    let post = this.props.post_view.post;
     return (
-      <div class="">
+      <div class="post-listing">
         {!this.state.showEdit ? (
           <>
             {this.listing()}
-            {this.body()}
+            {this.state.imageExpanded && this.img}
+            {post.url.isSome() &&
+              this.showBody &&
+              post.embed_title.isSome() && <MetadataCard post={post} />}
+            {this.showBody && this.body()}
           </>
         ) : (
           <div class="col-12">
             <PostForm
-              post_view={this.props.post_view}
+              post_view={Some(this.props.post_view)}
+              communities={None}
+              params={None}
               onEdit={this.handleEditPost}
               onCancel={this.handleEditCancel}
               enableNsfw={this.props.enableNsfw}
@@ -146,26 +176,41 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   body() {
-    let post = this.props.post_view.post;
-    return (
-      <div class="row">
-        <div class="col-12">
-          {post.url && this.showBody && post.embed_title && (
-            <MetadataCard post={post} />
+    return this.props.post_view.post.body.match({
+      some: body => (
+        <div class="col-12 card my-2 p-2">
+          {this.state.viewSource ? (
+            <pre>{body}</pre>
+          ) : (
+            <div className="md-div" dangerouslySetInnerHTML={mdToHtml(body)} />
           )}
-          {this.showBody &&
-            post.body &&
-            (this.state.viewSource ? (
-              <pre>{post.body}</pre>
-            ) : (
-              <div
-                className="md-div"
-                dangerouslySetInnerHTML={mdToHtml(post.body)}
-              />
-            ))}
         </div>
-      </div>
-    );
+      ),
+      none: <></>,
+    });
+  }
+
+  get img() {
+    return this.imageSrc.match({
+      some: src => (
+        <>
+          <div class="offset-sm-3 my-2 d-none d-sm-block">
+            <a href={src} class="d-inline-block">
+              <PictrsImage src={src} />
+            </a>
+          </div>
+          <div className="my-2 d-block d-sm-none">
+            <a
+              class="d-inline-block"
+              onClick={linkEvent(this, this.handleImageExpandClick)}
+            >
+              <PictrsImage src={src} />
+            </a>
+          </div>
+        </>
+      ),
+      none: <></>,
+    });
   }
 
   imgThumb(src: string) {
@@ -180,53 +225,58 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     );
   }
 
-  getImageSrc(): string {
+  get imageSrc(): Option<string> {
     let post = this.props.post_view.post;
-    if (isImage(post.url)) {
-      if (post.url.includes("pictrs")) {
-        return post.url;
-      } else if (post.thumbnail_url) {
-        return post.thumbnail_url;
+    let url = post.url;
+    let thumbnail = post.thumbnail_url;
+
+    if (url.isSome() && isImage(url.unwrap())) {
+      if (url.unwrap().includes("pictrs")) {
+        return url;
+      } else if (thumbnail.isSome()) {
+        return thumbnail;
       } else {
-        return post.url;
+        return url;
       }
-    } else if (post.thumbnail_url) {
-      return post.thumbnail_url;
+    } else if (thumbnail.isSome()) {
+      return thumbnail;
     } else {
-      return null;
+      return None;
     }
   }
 
   thumbnail() {
     let post = this.props.post_view.post;
+    let url = post.url;
+    let thumbnail = post.thumbnail_url;
 
-    if (isImage(post.url)) {
+    if (url.isSome() && isImage(url.unwrap())) {
       return (
-        <div
-          class="float-right text-body pointer d-inline-block position-relative mb-2"
+        <a
+          href={this.imageSrc.unwrap()}
+          class="text-body d-inline-block position-relative mb-2"
           data-tippy-content={i18n.t("expand_here")}
           onClick={linkEvent(this, this.handleImageExpandClick)}
-          role="button"
           aria-label={i18n.t("expand_here")}
         >
-          {this.imgThumb(this.getImageSrc())}
+          {this.imgThumb(this.imageSrc.unwrap())}
           <Icon icon="image" classes="mini-overlay" />
-        </div>
+        </a>
       );
-    } else if (post.thumbnail_url) {
+    } else if (url.isSome() && thumbnail.isSome()) {
       return (
         <a
-          class="float-right text-body d-inline-block position-relative mb-2"
-          href={post.url}
-          rel="noopener"
-          title={post.url}
+          class="text-body d-inline-block position-relative mb-2"
+          href={url.unwrap()}
+          rel={relTags}
+          title={url.unwrap()}
         >
-          {this.imgThumb(this.getImageSrc())}
+          {this.imgThumb(this.imageSrc.unwrap())}
           <Icon icon="external-link" classes="mini-overlay" />
         </a>
       );
-    } else if (post.url) {
-      if (isVideo(post.url)) {
+    } else if (url.isSome()) {
+      if (isVideo(url.unwrap())) {
         return (
           <div class="embed-responsive embed-responsive-16by9">
             <video
@@ -236,7 +286,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
               controls
               class="embed-responsive-item"
             >
-              <source src={post.url} type="video/mp4" />
+              <source src={url.unwrap()} type="video/mp4" />
             </video>
           </div>
         );
@@ -244,9 +294,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         return (
           <a
             className="text-body"
-            href={post.url}
-            title={post.url}
-            rel="noopener"
+            href={url.unwrap()}
+            title={url.unwrap()}
+            rel={relTags}
           >
             <div class="thumbnail rounded bg-light d-flex justify-content-center">
               <Icon icon="external-link" classes="d-flex align-items-center" />
@@ -276,14 +326,19 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         <li className="list-inline-item">
           <PersonListing person={post_view.creator} />
 
-          {this.isMod && (
+          {this.creatorIsMod_ && (
             <span className="mx-1 badge badge-light">{i18n.t("mod")}</span>
           )}
-          {this.isAdmin && (
+          {this.creatorIsAdmin_ && (
             <span className="mx-1 badge badge-light">{i18n.t("admin")}</span>
           )}
+          {post_view.creator.bot_account && (
+            <span className="mx-1 badge badge-light">
+              {i18n.t("bot_account").toLowerCase()}
+            </span>
+          )}
           {(post_view.creator_banned_from_community ||
-            post_view.creator.banned) && (
+            isBanned(post_view.creator)) && (
             <span className="mx-1 badge badge-danger">{i18n.t("banned")}</span>
           )}
           {post_view.creator_blocked && (
@@ -297,43 +352,51 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
           )}
         </li>
         <li className="list-inline-item">•</li>
-        {post_view.post.url && !(hostname(post_view.post.url) == externalHost) && (
-          <>
-            <li className="list-inline-item">
-              <a
-                className="text-muted font-italic"
-                href={post_view.post.url}
-                title={post_view.post.url}
-                rel="noopener"
-              >
-                {hostname(post_view.post.url)}
-              </a>
-            </li>
-            <li className="list-inline-item">•</li>
-          </>
-        )}
+        {post_view.post.url.match({
+          some: url =>
+            !(hostname(url) == externalHost) && (
+              <>
+                <li className="list-inline-item">
+                  <a
+                    className="text-muted font-italic"
+                    href={url}
+                    title={url}
+                    rel={relTags}
+                  >
+                    {hostname(url)}
+                  </a>
+                </li>
+                <li className="list-inline-item">•</li>
+              </>
+            ),
+          none: <></>,
+        })}
         <li className="list-inline-item">
           <span>
-            <MomentTime data={post_view.post} />
+            <MomentTime
+              published={post_view.post.published}
+              updated={post_view.post.updated}
+            />
           </span>
         </li>
-        {post_view.post.body && (
-          <>
-            <li className="list-inline-item">•</li>
-            <li className="list-inline-item">
-              <button
-                className="text-muted btn btn-sm btn-link p-0"
-                data-tippy-content={md.render(
-                  previewLines(post_view.post.body)
-                )}
-                data-tippy-allowHtml={true}
-                onClick={linkEvent(this, this.handleShowBody)}
-              >
-                <Icon icon="book-open" classes="icon-inline mr-1" />
-              </button>
-            </li>
-          </>
-        )}
+        {post_view.post.body.match({
+          some: body => (
+            <>
+              <li className="list-inline-item">•</li>
+              <li className="list-inline-item">
+                <button
+                  className="text-muted btn btn-sm btn-link p-0"
+                  data-tippy-content={md.render(body)}
+                  data-tippy-allowHtml={true}
+                  onClick={linkEvent(this, this.handleShowBody)}
+                >
+                  <Icon icon="book-open" classes="icon-inline mr-1" />
+                </button>
+              </li>
+            </>
+          ),
+          none: <></>,
+        })}
       </ul>
     );
   }
@@ -343,9 +406,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
       <div className={`vote-bar col-1 pr-0 small text-center`}>
         <button
           className={`btn-animate btn btn-link p-0 ${
-            this.state.my_vote == 1 ? "text-info" : "text-muted"
+            this.state.my_vote.unwrapOr(0) == 1 ? "text-info" : "text-muted"
           }`}
-          onClick={linkEvent(this, this.handlePostLike)}
+          onClick={this.handlePostLike}
           data-tippy-content={i18n.t("upvote")}
           aria-label={i18n.t("upvote")}
         >
@@ -356,7 +419,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
             class={`unselectable pointer font-weight-bold text-muted px-1`}
             data-tippy-content={this.pointsTippy}
           >
-            {this.state.score}
+            {numToSI(this.state.score)}
           </div>
         ) : (
           <div class="p-1"></div>
@@ -364,9 +427,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         {this.props.enableDownvotes && (
           <button
             className={`btn-animate btn btn-link p-0 ${
-              this.state.my_vote == -1 ? "text-danger" : "text-muted"
+              this.state.my_vote.unwrapOr(0) == -1
+                ? "text-danger"
+                : "text-muted"
             }`}
-            onClick={linkEvent(this, this.handlePostDisLike)}
+            onClick={this.handlePostDisLike}
             data-tippy-content={i18n.t("downvote")}
             aria-label={i18n.t("downvote")}
           >
@@ -382,51 +447,41 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     return (
       <div className="post-title overflow-hidden">
         <h5>
-          {this.showBody && post.url ? (
-            <a
-              className={!post.stickied ? "text-body" : "text-primary"}
-              href={post.url}
-              title={post.url}
-              rel="noopener"
-            >
-              {post.name}
-            </a>
-          ) : (
-            <Link
-              className={!post.stickied ? "text-body" : "text-primary"}
-              to={`/post/${post.id}`}
-              title={i18n.t("comments")}
+          {post.url.match({
+            some: url => (
+              <a
+                className={!post.stickied ? "text-body" : "text-primary"}
+                href={url}
+                title={url}
+                rel={relTags}
+              >
+                {post.name}
+              </a>
+            ),
+            none: (
+              <Link
+                className={!post.stickied ? "text-body" : "text-primary"}
+                to={`/post/${post.id}`}
+                title={i18n.t("comments")}
+              >
+                {post.name}
+              </Link>
+            ),
+          })}
+          {post.url.map(isImage).or(post.thumbnail_url).unwrapOr(false) && (
+            <button
+              class="btn btn-link text-monospace text-muted small d-inline-block ml-2"
+              data-tippy-content={i18n.t("expand_here")}
+              onClick={linkEvent(this, this.handleImageExpandClick)}
             >
-              {post.name}
-            </Link>
+              <Icon
+                icon={
+                  !this.state.imageExpanded ? "plus-square" : "minus-square"
+                }
+                classes="icon-inline"
+              />
+            </button>
           )}
-          {(isImage(post.url) || post.thumbnail_url) &&
-            (!this.state.imageExpanded ? (
-              <button
-                class="btn btn-link text-monospace text-muted small d-inline-block ml-2"
-                data-tippy-content={i18n.t("expand_here")}
-                onClick={linkEvent(this, this.handleImageExpandClick)}
-              >
-                <Icon icon="plus-square" classes="icon-inline" />
-              </button>
-            ) : (
-              <span>
-                <button
-                  class="btn btn-link text-monospace text-muted small d-inline-block ml-2"
-                  onClick={linkEvent(this, this.handleImageExpandClick)}
-                >
-                  <Icon icon="minus-square" classes="icon-inline" />
-                </button>
-                <div>
-                  <button
-                    class="btn btn-link d-inline-block"
-                    onClick={linkEvent(this, this.handleImageExpandClick)}
-                  >
-                    <PictrsImage src={this.getImageSrc()} />
-                  </button>
-                </div>
-              </span>
-            ))}
           {post.removed && (
             <small className="ml-2 text-muted font-italic">
               {i18n.t("removed")}
@@ -466,491 +521,488 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     );
   }
 
+  duplicatesLine() {
+    return this.props.duplicates.match({
+      some: dupes =>
+        dupes.length > 0 && (
+          <ul class="list-inline mb-1 small text-muted">
+            <>
+              <li className="list-inline-item mr-2">
+                {i18n.t("cross_posted_to")}
+              </li>
+              {dupes.map(pv => (
+                <li className="list-inline-item mr-2">
+                  <Link to={`/post/${pv.post.id}`}>
+                    {pv.community.local
+                      ? pv.community.name
+                      : `${pv.community.name}@${hostname(
+                          pv.community.actor_id
+                        )}`}
+                  </Link>
+                </li>
+              ))}
+            </>
+          </ul>
+        ),
+      none: <></>,
+    });
+  }
+
   commentsLine(mobile = false) {
-    let post_view = this.props.post_view;
+    let post = this.props.post_view.post;
     return (
-      <div class="d-flex justify-content-between justify-content-lg-start flex-wrap text-muted font-weight-bold mb-1">
-        <button class="btn btn-link text-muted p-0">
-          <Link
-            className="text-muted small"
-            title={i18n.t("number_of_comments", {
-              count: post_view.counts.comments,
-            })}
-            to={`/post/${post_view.post.id}?scrollToComments=true`}
+      <div class="d-flex justify-content-start flex-wrap text-muted font-weight-bold mb-1">
+        {this.commentsButton}
+        {!post.local && (
+          <a
+            className="btn btn-link btn-animate text-muted py-0"
+            title={i18n.t("link")}
+            href={post.ap_id}
           >
-            <Icon icon="message-square" classes="icon-inline mr-1" />
-            {i18n.t("number_of_comments", {
-              count: post_view.counts.comments,
-            })}
-          </Link>
-        </button>
-        {!mobile && (
+            <Icon icon="fedilink" inline />
+          </a>
+        )}
+        {mobile && !this.props.viewOnly && this.mobileVotes}
+        {UserService.Instance.myUserInfo.isSome() &&
+          !this.props.viewOnly &&
+          this.postActions(mobile)}
+      </div>
+    );
+  }
+
+  postActions(mobile = false) {
+    // Possible enhancement: Priority+ pattern instead of just hard coding which get hidden behind the show more button.
+    // Possible enhancement: Make each button a component.
+    let post_view = this.props.post_view;
+    return (
+      <>
+        {this.saveButton}
+        {this.crossPostButton}
+        {mobile && this.showMoreButton}
+        {(!mobile || this.state.showAdvanced) && (
           <>
-            {this.state.downvotes !== 0 && showScores() && (
-              <button
-                class="btn text-muted py-0 pr-0"
-                data-tippy-content={this.pointsTippy}
-                aria-label={i18n.t("downvote")}
-              >
-                <small>
-                  <Icon icon="arrow-down1" classes="icon-inline mr-1" />
-                  <span>{this.state.downvotes}</span>
-                </small>
-              </button>
+            {!this.myPost && (
+              <>
+                {this.reportButton}
+                {this.blockButton}
+              </>
             )}
-            {!this.showBody && (
-              <button
-                class="btn btn-link btn-animate text-muted py-0"
-                onClick={linkEvent(this, this.handleSavePostClick)}
-                data-tippy-content={
-                  post_view.saved ? i18n.t("unsave") : i18n.t("save")
-                }
-                aria-label={post_view.saved ? i18n.t("unsave") : i18n.t("save")}
-              >
-                <small>
-                  <Icon
-                    icon="star"
-                    classes={`icon-inline ${post_view.saved && "text-warning"}`}
-                  />
-                </small>
-              </button>
+            {this.myPost && (this.showBody || this.state.showAdvanced) && (
+              <>
+                {this.editButton}
+                {this.deleteButton}
+              </>
             )}
           </>
         )}
-        {/* This is an expanding spacer for mobile */}
-        <div className="flex-grow-1"></div>
-        {mobile && (
+        {this.state.showAdvanced && (
           <>
-            <div>
-              {showScores() ? (
-                <button
-                  className={`btn-animate btn py-0 px-1 ${
-                    this.state.my_vote == 1 ? "text-info" : "text-muted"
-                  }`}
-                  data-tippy-content={this.pointsTippy}
-                  onClick={linkEvent(this, this.handlePostLike)}
-                  aria-label={i18n.t("upvote")}
-                >
-                  <Icon icon="arrow-up1" classes="icon-inline small mr-2" />
-                  {this.state.upvotes}
-                </button>
-              ) : (
-                <button
-                  className={`btn-animate btn py-0 px-1 ${
-                    this.state.my_vote == 1 ? "text-info" : "text-muted"
-                  }`}
-                  onClick={linkEvent(this, this.handlePostLike)}
-                  aria-label={i18n.t("upvote")}
-                >
-                  <Icon icon="arrow-up1" classes="icon-inline small" />
-                </button>
-              )}
-              {this.props.enableDownvotes &&
-                (showScores() ? (
-                  <button
-                    className={`ml-2 btn-animate btn py-0 pl-1 ${
-                      this.state.my_vote == -1 ? "text-danger" : "text-muted"
-                    }`}
-                    onClick={linkEvent(this, this.handlePostDisLike)}
-                    data-tippy-content={this.pointsTippy}
-                    aria-label={i18n.t("downvote")}
-                  >
-                    <Icon icon="arrow-down1" classes="icon-inline small mr-2" />
-                    {this.state.downvotes !== 0 && (
-                      <span>{this.state.downvotes}</span>
-                    )}
-                  </button>
-                ) : (
-                  <button
-                    className={`ml-2 btn-animate btn py-0 pl-1 ${
-                      this.state.my_vote == -1 ? "text-danger" : "text-muted"
-                    }`}
-                    onClick={linkEvent(this, this.handlePostDisLike)}
-                    aria-label={i18n.t("downvote")}
-                  >
-                    <Icon icon="arrow-down1" classes="icon-inline small" />
-                  </button>
-                ))}
-            </div>
+            {this.showBody &&
+              post_view.post.body.isSome() &&
+              this.viewSourceButton}
+            {this.canModOnSelf_ && (
+              <>
+                {this.lockButton}
+                {this.stickyButton}
+              </>
+            )}
+            {(this.canMod_ || this.canAdmin_) && <>{this.modRemoveButton}</>}
+          </>
+        )}
+        {!mobile && this.showMoreButton}
+      </>
+    );
+  }
+
+  get commentsButton() {
+    let post_view = this.props.post_view;
+    return (
+      <button class="btn btn-link text-muted py-0 pl-0">
+        <Link
+          className="text-muted"
+          title={i18n.t("number_of_comments", {
+            count: post_view.counts.comments,
+            formattedCount: post_view.counts.comments,
+          })}
+          to={`/post/${post_view.post.id}?scrollToComments=true`}
+        >
+          <Icon icon="message-square" classes="mr-1" inline />
+          {i18n.t("number_of_comments", {
+            count: post_view.counts.comments,
+            formattedCount: numToSI(post_view.counts.comments),
+          })}
+        </Link>
+      </button>
+    );
+  }
+
+  get mobileVotes() {
+    // TODO: make nicer
+    let tippy = showScores() ? { "data-tippy-content": this.pointsTippy } : {};
+    return (
+      <>
+        <div>
+          <button
+            className={`btn-animate btn py-0 px-1 ${
+              this.state.my_vote.unwrapOr(0) == 1 ? "text-info" : "text-muted"
+            }`}
+            {...tippy}
+            onClick={this.handlePostLike}
+            aria-label={i18n.t("upvote")}
+          >
+            <Icon icon="arrow-up1" classes="icon-inline small" />
+            {showScores() && (
+              <span class="ml-2">{numToSI(this.state.upvotes)}</span>
+            )}
+          </button>
+          {this.props.enableDownvotes && (
             <button
-              class="btn btn-link btn-animate text-muted py-0 pl-1 pr-0"
-              onClick={linkEvent(this, this.handleSavePostClick)}
-              aria-label={post_view.saved ? i18n.t("unsave") : i18n.t("save")}
-              data-tippy-content={
-                post_view.saved ? i18n.t("unsave") : i18n.t("save")
-              }
+              className={`ml-2 btn-animate btn py-0 px-1 ${
+                this.state.my_vote.unwrapOr(0) == -1
+                  ? "text-danger"
+                  : "text-muted"
+              }`}
+              onClick={this.handlePostDisLike}
+              {...tippy}
+              aria-label={i18n.t("downvote")}
             >
-              <Icon
-                icon="star"
-                classes={`icon-inline ${post_view.saved && "text-warning"}`}
-              />
+              <Icon icon="arrow-down1" classes="icon-inline small" />
+              {showScores() && (
+                <span
+                  class={classNames("ml-2", {
+                    invisible: this.state.downvotes === 0,
+                  })}
+                >
+                  {numToSI(this.state.downvotes)}
+                </span>
+              )}
             </button>
+          )}
+        </div>
+      </>
+    );
+  }
 
-            {!this.state.showMoreMobile && this.showBody && (
-              <button
-                class="btn btn-link btn-animate text-muted py-0"
-                onClick={linkEvent(this, this.handleShowMoreMobile)}
-                aria-label={i18n.t("more")}
-                data-tippy-content={i18n.t("more")}
-              >
-                <Icon icon="more-vertical" classes="icon-inline" />
-              </button>
-            )}
-            {this.state.showMoreMobile && this.postActions(mobile)}
-          </>
-        )}
-      </div>
+  get saveButton() {
+    let saved = this.props.post_view.saved;
+    let label = saved ? i18n.t("unsave") : i18n.t("save");
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleSavePostClick)}
+        data-tippy-content={label}
+        aria-label={label}
+      >
+        <Icon
+          icon="star"
+          classes={classNames({ "text-warning": saved })}
+          inline
+        />
+      </button>
     );
   }
 
-  duplicatesLine() {
-    let dupes = this.props.duplicates;
+  get crossPostButton() {
     return (
-      dupes &&
-      dupes.length > 0 && (
-        <ul class="list-inline mb-1 small text-muted">
-          <>
-            <li className="list-inline-item mr-2">
-              {i18n.t("cross_posted_to")}
-            </li>
-            {dupes.map(pv => (
-              <li className="list-inline-item mr-2">
-                <Link to={`/post/${pv.post.id}`}>
-                  {pv.community.local
-                    ? pv.community.name
-                    : `${pv.community.name}@${hostname(pv.community.actor_id)}`}
-                </Link>
-              </li>
-            ))}
-          </>
-        </ul>
-      )
+      <Link
+        className="btn btn-link btn-animate text-muted py-0"
+        to={`/create_post${this.crossPostParams}`}
+        title={i18n.t("cross_post")}
+      >
+        <Icon icon="copy" inline />
+      </Link>
     );
   }
 
-  postActions(mobile = false) {
+  get reportButton() {
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleShowReportDialog)}
+        data-tippy-content={i18n.t("show_report_dialog")}
+        aria-label={i18n.t("show_report_dialog")}
+      >
+        <Icon icon="flag" inline />
+      </button>
+    );
+  }
+
+  get blockButton() {
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleBlockUserClick)}
+        data-tippy-content={i18n.t("block_user")}
+        aria-label={i18n.t("block_user")}
+      >
+        <Icon icon="slash" inline />
+      </button>
+    );
+  }
+
+  get editButton() {
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleEditClick)}
+        data-tippy-content={i18n.t("edit")}
+        aria-label={i18n.t("edit")}
+      >
+        <Icon icon="edit" inline />
+      </button>
+    );
+  }
+
+  get deleteButton() {
+    let deleted = this.props.post_view.post.deleted;
+    let label = !deleted ? i18n.t("delete") : i18n.t("restore");
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleDeleteClick)}
+        data-tippy-content={label}
+        aria-label={label}
+      >
+        <Icon
+          icon="trash"
+          classes={classNames({ "text-danger": deleted })}
+          inline
+        />
+      </button>
+    );
+  }
+
+  get showMoreButton() {
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleShowAdvanced)}
+        data-tippy-content={i18n.t("more")}
+        aria-label={i18n.t("more")}
+      >
+        <Icon icon="more-vertical" inline />
+      </button>
+    );
+  }
+
+  get viewSourceButton() {
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleViewSource)}
+        data-tippy-content={i18n.t("view_source")}
+        aria-label={i18n.t("view_source")}
+      >
+        <Icon
+          icon="file-text"
+          classes={classNames({ "text-success": this.state.viewSource })}
+          inline
+        />
+      </button>
+    );
+  }
+
+  get lockButton() {
+    let locked = this.props.post_view.post.locked;
+    let label = locked ? i18n.t("unlock") : i18n.t("lock");
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleModLock)}
+        data-tippy-content={label}
+        aria-label={label}
+      >
+        <Icon
+          icon="lock"
+          classes={classNames({ "text-danger": locked })}
+          inline
+        />
+      </button>
+    );
+  }
+
+  get stickyButton() {
+    let stickied = this.props.post_view.post.stickied;
+    let label = stickied ? i18n.t("unsticky") : i18n.t("sticky");
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(this, this.handleModSticky)}
+        data-tippy-content={label}
+        aria-label={label}
+      >
+        <Icon
+          icon="pin"
+          classes={classNames({ "text-success": stickied })}
+          inline
+        />
+      </button>
+    );
+  }
+
+  get modRemoveButton() {
+    let removed = this.props.post_view.post.removed;
+    return (
+      <button
+        class="btn btn-link btn-animate text-muted py-0"
+        onClick={linkEvent(
+          this,
+          !removed ? this.handleModRemoveShow : this.handleModRemoveSubmit
+        )}
+      >
+        {/* TODO: Find an icon for this. */}
+        {!removed ? i18n.t("remove") : i18n.t("restore")}
+      </button>
+    );
+  }
+
+  /**
+   * Mod/Admin actions to be taken against the author.
+   */
+  userActionsLine() {
+    // TODO: make nicer
     let post_view = this.props.post_view;
     return (
-      UserService.Instance.myUserInfo && (
+      this.state.showAdvanced && (
         <>
-          {this.showBody && (
+          {this.canMod_ && (
             <>
-              {!mobile && (
+              {!this.creatorIsMod_ &&
+                (!post_view.creator_banned_from_community ? (
+                  <button
+                    class="btn btn-link btn-animate text-muted py-0"
+                    onClick={linkEvent(
+                      this,
+                      this.handleModBanFromCommunityShow
+                    )}
+                    aria-label={i18n.t("ban")}
+                  >
+                    {i18n.t("ban")}
+                  </button>
+                ) : (
+                  <button
+                    class="btn btn-link btn-animate text-muted py-0"
+                    onClick={linkEvent(
+                      this,
+                      this.handleModBanFromCommunitySubmit
+                    )}
+                    aria-label={i18n.t("unban")}
+                  >
+                    {i18n.t("unban")}
+                  </button>
+                ))}
+              {!post_view.creator_banned_from_community && (
                 <button
-                  class="btn btn-link btn-animate text-muted py-0 pl-0"
-                  onClick={linkEvent(this, this.handleSavePostClick)}
-                  data-tippy-content={
-                    post_view.saved ? i18n.t("unsave") : i18n.t("save")
-                  }
+                  class="btn btn-link btn-animate text-muted py-0"
+                  onClick={linkEvent(this, this.handleAddModToCommunity)}
                   aria-label={
-                    post_view.saved ? i18n.t("unsave") : i18n.t("save")
+                    this.creatorIsMod_
+                      ? i18n.t("remove_as_mod")
+                      : i18n.t("appoint_as_mod")
                   }
                 >
-                  <Icon
-                    icon="star"
-                    classes={`icon-inline ${post_view.saved && "text-warning"}`}
-                  />
-                </button>
-              )}
-              <Link
-                className="btn btn-link btn-animate text-muted py-0"
-                to={`/create_post${this.crossPostParams}`}
-                title={i18n.t("cross_post")}
-              >
-                <Icon icon="copy" classes="icon-inline" />
-              </Link>
-              {!this.myPost && (
-                <button
-                  class="btn btn-link btn-animate text-muted py-0"
-                  onClick={linkEvent(this, this.handleBlockUserClick)}
-                  data-tippy-content={i18n.t("block_user")}
-                  aria-label={i18n.t("block_user")}
-                >
-                  <Icon icon="slash" classes="icon-inline" />
+                  {this.creatorIsMod_
+                    ? i18n.t("remove_as_mod")
+                    : i18n.t("appoint_as_mod")}
                 </button>
               )}
             </>
           )}
-          {this.myPost && this.showBody && (
-            <>
+          {/* Community creators and admins can transfer community to another mod */}
+          {(amCommunityCreator(this.props.moderators, post_view.creator.id) ||
+            this.canAdmin_) &&
+            this.creatorIsMod_ &&
+            (!this.state.showConfirmTransferCommunity ? (
               <button
                 class="btn btn-link btn-animate text-muted py-0"
-                onClick={linkEvent(this, this.handleEditClick)}
-                data-tippy-content={i18n.t("edit")}
-                aria-label={i18n.t("edit")}
-              >
-                <Icon icon="edit" classes="icon-inline" />
-              </button>
-              <button
-                class="btn btn-link btn-animate text-muted py-0"
-                onClick={linkEvent(this, this.handleDeleteClick)}
-                data-tippy-content={
-                  !post_view.post.deleted ? i18n.t("delete") : i18n.t("restore")
-                }
-                aria-label={
-                  !post_view.post.deleted ? i18n.t("delete") : i18n.t("restore")
-                }
+                onClick={linkEvent(
+                  this,
+                  this.handleShowConfirmTransferCommunity
+                )}
+                aria-label={i18n.t("transfer_community")}
               >
-                <Icon
-                  icon="trash"
-                  classes={`icon-inline ${
-                    post_view.post.deleted && "text-danger"
-                  }`}
-                />
+                {i18n.t("transfer_community")}
               </button>
-            </>
-          )}
-
-          {!this.state.showAdvanced && this.showBody ? (
-            <button
-              class="btn btn-link btn-animate text-muted py-0"
-              onClick={linkEvent(this, this.handleShowAdvanced)}
-              data-tippy-content={i18n.t("more")}
-              aria-label={i18n.t("more")}
-            >
-              <Icon icon="more-vertical" classes="icon-inline" />
-            </button>
-          ) : (
-            <>
-              {this.showBody && post_view.post.body && (
+            ) : (
+              <>
                 <button
-                  class="btn btn-link btn-animate text-muted py-0"
-                  onClick={linkEvent(this, this.handleViewSource)}
-                  data-tippy-content={i18n.t("view_source")}
-                  aria-label={i18n.t("view_source")}
+                  class="d-inline-block mr-1 btn btn-link btn-animate text-muted py-0"
+                  aria-label={i18n.t("are_you_sure")}
                 >
-                  <Icon
-                    icon="file-text"
-                    classes={`icon-inline ${
-                      this.state.viewSource && "text-success"
-                    }`}
-                  />
+                  {i18n.t("are_you_sure")}
                 </button>
-              )}
-              {this.canModOnSelf && (
-                <>
-                  <button
-                    class="btn btn-link btn-animate text-muted py-0"
-                    onClick={linkEvent(this, this.handleModLock)}
-                    data-tippy-content={
-                      post_view.post.locked ? i18n.t("unlock") : i18n.t("lock")
-                    }
-                    aria-label={
-                      post_view.post.locked ? i18n.t("unlock") : i18n.t("lock")
-                    }
-                  >
-                    <Icon
-                      icon="lock"
-                      classes={`icon-inline ${
-                        post_view.post.locked && "text-danger"
-                      }`}
-                    />
-                  </button>
-                  <button
-                    class="btn btn-link btn-animate text-muted py-0"
-                    onClick={linkEvent(this, this.handleModSticky)}
-                    data-tippy-content={
-                      post_view.post.stickied
-                        ? i18n.t("unsticky")
-                        : i18n.t("sticky")
-                    }
-                    aria-label={
-                      post_view.post.stickied
-                        ? i18n.t("unsticky")
-                        : i18n.t("sticky")
-                    }
-                  >
-                    <Icon
-                      icon="pin"
-                      classes={`icon-inline ${
-                        post_view.post.stickied && "text-success"
-                      }`}
-                    />
-                  </button>
-                </>
-              )}
-              {/* Mods can ban from community, and appoint as mods to community */}
-              {(this.canMod || this.canAdmin) &&
-                (!post_view.post.removed ? (
-                  <button
-                    class="btn btn-link btn-animate text-muted py-0"
-                    onClick={linkEvent(this, this.handleModRemoveShow)}
-                    aria-label={i18n.t("remove")}
-                  >
-                    {i18n.t("remove")}
-                  </button>
-                ) : (
-                  <button
-                    class="btn btn-link btn-animate text-muted py-0"
-                    onClick={linkEvent(this, this.handleModRemoveSubmit)}
-                    aria-label={i18n.t("restore")}
-                  >
-                    {i18n.t("restore")}
-                  </button>
-                ))}
-              {this.canMod && (
+                <button
+                  class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
+                  aria-label={i18n.t("yes")}
+                  onClick={linkEvent(this, this.handleTransferCommunity)}
+                >
+                  {i18n.t("yes")}
+                </button>
+                <button
+                  class="btn btn-link btn-animate text-muted py-0 d-inline-block"
+                  onClick={linkEvent(
+                    this,
+                    this.handleCancelShowConfirmTransferCommunity
+                  )}
+                  aria-label={i18n.t("no")}
+                >
+                  {i18n.t("no")}
+                </button>
+              </>
+            ))}
+          {/* Admins can ban from all, and appoint other admins */}
+          {this.canAdmin_ && (
+            <>
+              {!this.creatorIsAdmin_ && (
                 <>
-                  {!this.isMod &&
-                    (!post_view.creator_banned_from_community ? (
-                      <button
-                        class="btn btn-link btn-animate text-muted py-0"
-                        onClick={linkEvent(
-                          this,
-                          this.handleModBanFromCommunityShow
-                        )}
-                        aria-label={i18n.t("ban")}
-                      >
-                        {i18n.t("ban")}
-                      </button>
-                    ) : (
-                      <button
-                        class="btn btn-link btn-animate text-muted py-0"
-                        onClick={linkEvent(
-                          this,
-                          this.handleModBanFromCommunitySubmit
-                        )}
-                        aria-label={i18n.t("unban")}
-                      >
-                        {i18n.t("unban")}
-                      </button>
-                    ))}
-                  {!post_view.creator_banned_from_community && (
+                  {!isBanned(post_view.creator) ? (
                     <button
                       class="btn btn-link btn-animate text-muted py-0"
-                      onClick={linkEvent(this, this.handleAddModToCommunity)}
-                      aria-label={
-                        this.isMod
-                          ? i18n.t("remove_as_mod")
-                          : i18n.t("appoint_as_mod")
-                      }
-                    >
-                      {this.isMod
-                        ? i18n.t("remove_as_mod")
-                        : i18n.t("appoint_as_mod")}
-                    </button>
-                  )}
-                </>
-              )}
-              {/* Community creators and admins can transfer community to another mod */}
-              {(this.amCommunityCreator || this.canAdmin) &&
-                this.isMod &&
-                (!this.state.showConfirmTransferCommunity ? (
-                  <button
-                    class="btn btn-link btn-animate text-muted py-0"
-                    onClick={linkEvent(
-                      this,
-                      this.handleShowConfirmTransferCommunity
-                    )}
-                    aria-label={i18n.t("transfer_community")}
-                  >
-                    {i18n.t("transfer_community")}
-                  </button>
-                ) : (
-                  <>
-                    <button
-                      class="d-inline-block mr-1 btn btn-link btn-animate text-muted py-0"
-                      aria-label={i18n.t("are_you_sure")}
-                    >
-                      {i18n.t("are_you_sure")}
-                    </button>
-                    <button
-                      class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
-                      aria-label={i18n.t("yes")}
-                      onClick={linkEvent(this, this.handleTransferCommunity)}
-                    >
-                      {i18n.t("yes")}
-                    </button>
-                    <button
-                      class="btn btn-link btn-animate text-muted py-0 d-inline-block"
-                      onClick={linkEvent(
-                        this,
-                        this.handleCancelShowConfirmTransferCommunity
-                      )}
-                      aria-label={i18n.t("no")}
+                      onClick={linkEvent(this, this.handleModBanShow)}
+                      aria-label={i18n.t("ban_from_site")}
                     >
-                      {i18n.t("no")}
+                      {i18n.t("ban_from_site")}
                     </button>
-                  </>
-                ))}
-              {/* Admins can ban from all, and appoint other admins */}
-              {this.canAdmin && (
-                <>
-                  {!this.isAdmin &&
-                    (!post_view.creator.banned ? (
-                      <button
-                        class="btn btn-link btn-animate text-muted py-0"
-                        onClick={linkEvent(this, this.handleModBanShow)}
-                        aria-label={i18n.t("ban_from_site")}
-                      >
-                        {i18n.t("ban_from_site")}
-                      </button>
-                    ) : (
-                      <button
-                        class="btn btn-link btn-animate text-muted py-0"
-                        onClick={linkEvent(this, this.handleModBanSubmit)}
-                        aria-label={i18n.t("unban_from_site")}
-                      >
-                        {i18n.t("unban_from_site")}
-                      </button>
-                    ))}
-                  {!post_view.creator.banned && post_view.creator.local && (
+                  ) : (
                     <button
                       class="btn btn-link btn-animate text-muted py-0"
-                      onClick={linkEvent(this, this.handleAddAdmin)}
-                      aria-label={
-                        this.isAdmin
-                          ? i18n.t("remove_as_admin")
-                          : i18n.t("appoint_as_admin")
-                      }
+                      onClick={linkEvent(this, this.handleModBanSubmit)}
+                      aria-label={i18n.t("unban_from_site")}
                     >
-                      {this.isAdmin
-                        ? i18n.t("remove_as_admin")
-                        : i18n.t("appoint_as_admin")}
+                      {i18n.t("unban_from_site")}
                     </button>
                   )}
-                </>
-              )}
-              {/* Site Creator can transfer to another admin */}
-              {this.amSiteCreator &&
-                this.isAdmin &&
-                (!this.state.showConfirmTransferSite ? (
                   <button
                     class="btn btn-link btn-animate text-muted py-0"
-                    onClick={linkEvent(
-                      this,
-                      this.handleShowConfirmTransferSite
-                    )}
-                    aria-label={i18n.t("transfer_site")}
+                    onClick={linkEvent(this, this.handlePurgePersonShow)}
+                    aria-label={i18n.t("purge_user")}
                   >
-                    {i18n.t("transfer_site")}
+                    {i18n.t("purge_user")}
                   </button>
-                ) : (
-                  <>
-                    <button
-                      class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
-                      aria-label={i18n.t("are_you_sure")}
-                    >
-                      {i18n.t("are_you_sure")}
-                    </button>
-                    <button
-                      class="btn btn-link btn-animate text-muted py-0 d-inline-block mr-1"
-                      onClick={linkEvent(this, this.handleTransferSite)}
-                      aria-label={i18n.t("yes")}
-                    >
-                      {i18n.t("yes")}
-                    </button>
-                    <button
-                      class="btn btn-link btn-animate text-muted py-0 d-inline-block"
-                      onClick={linkEvent(
-                        this,
-                        this.handleCancelShowConfirmTransferSite
-                      )}
-                      aria-label={i18n.t("no")}
-                    >
-                      {i18n.t("no")}
-                    </button>
-                  </>
-                ))}
+                  <button
+                    class="btn btn-link btn-animate text-muted py-0"
+                    onClick={linkEvent(this, this.handlePurgePostShow)}
+                    aria-label={i18n.t("purge_post")}
+                  >
+                    {i18n.t("purge_post")}
+                  </button>
+                </>
+              )}
+              {!isBanned(post_view.creator) && post_view.creator.local && (
+                <button
+                  class="btn btn-link btn-animate text-muted py-0"
+                  onClick={linkEvent(this, this.handleAddAdmin)}
+                  aria-label={
+                    this.creatorIsAdmin_
+                      ? i18n.t("remove_as_admin")
+                      : i18n.t("appoint_as_admin")
+                  }
+                >
+                  {this.creatorIsAdmin_
+                    ? i18n.t("remove_as_admin")
+                    : i18n.t("appoint_as_admin")}
+                </button>
+              )}
             </>
           )}
         </>
@@ -960,6 +1012,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
 
   removeAndBanDialogs() {
     let post = this.props.post_view;
+    let purgeTypeText: string;
+    if (this.state.purgeType == PurgeType.Post) {
+      purgeTypeText = i18n.t("purge_post");
+    } else if (this.state.purgeType == PurgeType.Person) {
+      purgeTypeText = `${i18n.t("purge")} ${post.creator.name}`;
+    }
     return (
       <>
         {this.state.showRemoveDialog && (
@@ -975,7 +1033,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
               id="post-listing-remove-reason"
               class="form-control mr-2"
               placeholder={i18n.t("reason")}
-              value={this.state.removeReason}
+              value={toUndefined(this.state.removeReason)}
               onInput={linkEvent(this, this.handleModRemoveReasonChange)}
             />
             <button
@@ -989,7 +1047,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         )}
         {this.state.showBanDialog && (
           <form onSubmit={linkEvent(this, this.handleModBanBothSubmit)}>
-            <div class="form-group row">
+            <div class="form-group row col-12">
               <label class="col-form-label" htmlFor="post-listing-ban-reason">
                 {i18n.t("reason")}
               </label>
@@ -998,9 +1056,20 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
                 id="post-listing-ban-reason"
                 class="form-control mr-2"
                 placeholder={i18n.t("reason")}
-                value={this.state.banReason}
+                value={toUndefined(this.state.banReason)}
                 onInput={linkEvent(this, this.handleModBanReasonChange)}
               />
+              <label class="col-form-label" htmlFor={`mod-ban-expires`}>
+                {i18n.t("expires")}
+              </label>
+              <input
+                type="number"
+                id={`mod-ban-expires`}
+                class="form-control mr-2"
+                placeholder={i18n.t("number_of_days")}
+                value={toUndefined(this.state.banExpireDays)}
+                onInput={linkEvent(this, this.handleModBanExpireDaysChange)}
+              />
               <div class="form-group">
                 <div class="form-check">
                   <input
@@ -1036,13 +1105,70 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
             </div>
           </form>
         )}
+        {this.state.showReportDialog && (
+          <form
+            class="form-inline"
+            onSubmit={linkEvent(this, this.handleReportSubmit)}
+          >
+            <label class="sr-only" htmlFor="post-report-reason">
+              {i18n.t("reason")}
+            </label>
+            <input
+              type="text"
+              id="post-report-reason"
+              class="form-control mr-2"
+              placeholder={i18n.t("reason")}
+              required
+              value={toUndefined(this.state.reportReason)}
+              onInput={linkEvent(this, this.handleReportReasonChange)}
+            />
+            <button
+              type="submit"
+              class="btn btn-secondary"
+              aria-label={i18n.t("create_report")}
+            >
+              {i18n.t("create_report")}
+            </button>
+          </form>
+        )}
+        {this.state.showPurgeDialog && (
+          <form
+            class="form-inline"
+            onSubmit={linkEvent(this, this.handlePurgeSubmit)}
+          >
+            <PurgeWarning />
+            <label class="sr-only" htmlFor="purge-reason">
+              {i18n.t("reason")}
+            </label>
+            <input
+              type="text"
+              id="purge-reason"
+              class="form-control mr-2"
+              placeholder={i18n.t("reason")}
+              value={toUndefined(this.state.purgeReason)}
+              onInput={linkEvent(this, this.handlePurgeReasonChange)}
+            />
+            {this.state.purgeLoading ? (
+              <Spinner />
+            ) : (
+              <button
+                type="submit"
+                class="btn btn-secondary"
+                aria-label={purgeTypeText}
+              >
+                {purgeTypeText}
+              </button>
+            )}
+          </form>
+        )}
       </>
     );
   }
 
   mobileThumbnail() {
     let post = this.props.post_view.post;
-    return post.thumbnail_url || isImage(post.url) ? (
+    return post.thumbnail_url.isSome() ||
+      post.url.map(isImage).unwrapOr(false) ? (
       <div class="row">
         <div className={`${this.state.imageExpanded ? "col-12" : "col-8"}`}>
           {this.postTitleLine()}
@@ -1060,15 +1186,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   showMobilePreview() {
     let post = this.props.post_view.post;
     return (
-      post.body &&
-      !this.showBody && (
-        <div
-          className="md-div mb-1"
-          dangerouslySetInnerHTML={{
-            __html: md.render(previewLines(post.body)),
-          }}
-        />
-      )
+      !this.showBody &&
+      post.body.match({
+        some: body => <div className="md-div mb-1 preview-lines">{body}</div>,
+        none: <></>,
+      })
     );
   }
 
@@ -1088,6 +1210,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
               {this.showMobilePreview()}
 
               {this.commentsLine(true)}
+              {this.userActionsLine()}
               {this.duplicatesLine()}
               {this.removeAndBanDialogs()}
             </div>
@@ -1097,24 +1220,18 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
         {/* The larger view*/}
         <div class="d-none d-sm-block">
           <div class="row">
-            {this.voteBar()}
-            {!this.state.imageExpanded && (
-              <div class="col-sm-2 pr-0">
-                <div class="">{this.thumbnail()}</div>
-              </div>
-            )}
-            <div
-              class={`${
-                this.state.imageExpanded ? "col-12" : "col-12 col-sm-9"
-              }`}
-            >
+            {!this.props.viewOnly && this.voteBar()}
+            <div class="col-sm-2 pr-0">
+              <div class="">{this.thumbnail()}</div>
+            </div>
+            <div class="col-12 col-sm-9">
               <div class="row">
                 <div className="col-12">
                   {this.postTitleLine()}
                   {this.createdLine()}
                   {this.commentsLine()}
                   {this.duplicatesLine()}
-                  {this.postActions()}
+                  {this.userActionsLine()}
                   {this.removeAndBanDialogs()}
                 </div>
               </div>
@@ -1126,162 +1243,78 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   private get myPost(): boolean {
-    return (
-      UserService.Instance.myUserInfo &&
-      this.props.post_view.creator.id ==
-        UserService.Instance.myUserInfo.local_user_view.person.id
-    );
-  }
-
-  get isMod(): boolean {
-    return (
-      this.props.moderators &&
-      isMod(
-        this.props.moderators.map(m => m.moderator.id),
-        this.props.post_view.creator.id
-      )
-    );
-  }
-
-  get isAdmin(): boolean {
-    return (
-      this.props.admins &&
-      isMod(
-        this.props.admins.map(a => a.person.id),
-        this.props.post_view.creator.id
-      )
-    );
-  }
-
-  get canMod(): boolean {
-    if (this.props.admins && this.props.moderators) {
-      let adminsThenMods = this.props.admins
-        .map(a => a.person.id)
-        .concat(this.props.moderators.map(m => m.moderator.id));
-
-      return canMod(
-        UserService.Instance.myUserInfo,
-        adminsThenMods,
-        this.props.post_view.creator.id
-      );
-    } else {
-      return false;
-    }
-  }
-
-  get canModOnSelf(): boolean {
-    if (this.props.admins && this.props.moderators) {
-      let adminsThenMods = this.props.admins
-        .map(a => a.person.id)
-        .concat(this.props.moderators.map(m => m.moderator.id));
-
-      return canMod(
-        UserService.Instance.myUserInfo,
-        adminsThenMods,
-        this.props.post_view.creator.id,
-        true
-      );
-    } else {
-      return false;
-    }
-  }
-
-  get canAdmin(): boolean {
-    return (
-      this.props.admins &&
-      canMod(
-        UserService.Instance.myUserInfo,
-        this.props.admins.map(a => a.person.id),
-        this.props.post_view.creator.id
-      )
-    );
-  }
-
-  get amCommunityCreator(): boolean {
-    return (
-      this.props.moderators &&
-      UserService.Instance.myUserInfo &&
-      this.props.post_view.creator.id !=
-        UserService.Instance.myUserInfo.local_user_view.person.id &&
-      UserService.Instance.myUserInfo.local_user_view.person.id ==
-        this.props.moderators[0].moderator.id
-    );
-  }
-
-  get amSiteCreator(): boolean {
-    return (
-      this.props.admins &&
-      UserService.Instance.myUserInfo &&
-      this.props.post_view.creator.id !=
-        UserService.Instance.myUserInfo.local_user_view.person.id &&
-      UserService.Instance.myUserInfo.local_user_view.person.id ==
-        this.props.admins[0].person.id
-    );
+    return UserService.Instance.myUserInfo.match({
+      some: mui =>
+        this.props.post_view.creator.id == mui.local_user_view.person.id,
+      none: false,
+    });
   }
 
-  handlePostLike(i: PostListing, event: any) {
+  handlePostLike(event: any) {
     event.preventDefault();
-    if (!UserService.Instance.myUserInfo) {
+    if (UserService.Instance.myUserInfo.isNone()) {
       this.context.router.history.push(`/login`);
     }
 
-    let new_vote = i.state.my_vote == 1 ? 0 : 1;
+    let myVote = this.state.my_vote.unwrapOr(0);
+    let newVote = myVote == 1 ? 0 : 1;
 
-    if (i.state.my_vote == 1) {
-      i.state.score--;
-      i.state.upvotes--;
-    } else if (i.state.my_vote == -1) {
-      i.state.downvotes--;
-      i.state.upvotes++;
-      i.state.score += 2;
+    if (myVote == 1) {
+      this.state.score--;
+      this.state.upvotes--;
+    } else if (myVote == -1) {
+      this.state.downvotes--;
+      this.state.upvotes++;
+      this.state.score += 2;
     } else {
-      i.state.upvotes++;
-      i.state.score++;
+      this.state.upvotes++;
+      this.state.score++;
     }
 
-    i.state.my_vote = new_vote;
+    this.state.my_vote = Some(newVote);
 
-    let form: CreatePostLike = {
-      post_id: i.props.post_view.post.id,
-      score: i.state.my_vote,
-      auth: authField(),
-    };
+    let form = new CreatePostLike({
+      post_id: this.props.post_view.post.id,
+      score: newVote,
+      auth: auth().unwrap(),
+    });
 
     WebSocketService.Instance.send(wsClient.likePost(form));
-    i.setState(i.state);
+    this.setState(this.state);
     setupTippy();
   }
 
-  handlePostDisLike(i: PostListing, event: any) {
+  handlePostDisLike(event: any) {
     event.preventDefault();
-    if (!UserService.Instance.myUserInfo) {
+    if (UserService.Instance.myUserInfo.isNone()) {
       this.context.router.history.push(`/login`);
     }
 
-    let new_vote = i.state.my_vote == -1 ? 0 : -1;
+    let myVote = this.state.my_vote.unwrapOr(0);
+    let newVote = myVote == -1 ? 0 : -1;
 
-    if (i.state.my_vote == 1) {
-      i.state.score -= 2;
-      i.state.upvotes--;
-      i.state.downvotes++;
-    } else if (i.state.my_vote == -1) {
-      i.state.downvotes--;
-      i.state.score++;
+    if (myVote == 1) {
+      this.state.score -= 2;
+      this.state.upvotes--;
+      this.state.downvotes++;
+    } else if (myVote == -1) {
+      this.state.downvotes--;
+      this.state.score++;
     } else {
-      i.state.downvotes++;
-      i.state.score--;
+      this.state.downvotes++;
+      this.state.score--;
     }
 
-    i.state.my_vote = new_vote;
+    this.state.my_vote = Some(newVote);
 
-    let form: CreatePostLike = {
-      post_id: i.props.post_view.post.id,
-      score: i.state.my_vote,
-      auth: authField(),
-    };
+    let form = new CreatePostLike({
+      post_id: this.props.post_view.post.id,
+      score: newVote,
+      auth: auth().unwrap(),
+    });
 
     WebSocketService.Instance.send(wsClient.likePost(form));
-    i.setState(i.state);
+    this.setState(this.state);
     setupTippy();
   }
 
@@ -1301,32 +1334,55 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     this.setState(this.state);
   }
 
+  handleShowReportDialog(i: PostListing) {
+    i.state.showReportDialog = !i.state.showReportDialog;
+    i.setState(this.state);
+  }
+
+  handleReportReasonChange(i: PostListing, event: any) {
+    i.state.reportReason = Some(event.target.value);
+    i.setState(i.state);
+  }
+
+  handleReportSubmit(i: PostListing, event: any) {
+    event.preventDefault();
+    let form = new CreatePostReport({
+      post_id: i.props.post_view.post.id,
+      reason: toUndefined(i.state.reportReason),
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.createPostReport(form));
+
+    i.state.showReportDialog = false;
+    i.setState(i.state);
+  }
+
   handleBlockUserClick(i: PostListing) {
-    let blockUserForm: BlockPerson = {
+    let blockUserForm = new BlockPerson({
       person_id: i.props.post_view.creator.id,
       block: true,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.blockPerson(blockUserForm));
   }
 
   handleDeleteClick(i: PostListing) {
-    let deleteForm: DeletePost = {
+    let deleteForm = new DeletePost({
       post_id: i.props.post_view.post.id,
       deleted: !i.props.post_view.post.deleted,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.deletePost(deleteForm));
   }
 
   handleSavePostClick(i: PostListing) {
     let saved =
       i.props.post_view.saved == undefined ? true : !i.props.post_view.saved;
-    let form: SavePost = {
+    let form = new SavePost({
       post_id: i.props.post_view.post.id,
       save: saved,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
 
     WebSocketService.Instance.send(wsClient.savePost(form));
   }
@@ -1335,10 +1391,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     let post = this.props.post_view.post;
     let params = `?title=${encodeURIComponent(post.name)}`;
 
-    if (post.url) {
-      params += `&url=${encodeURIComponent(post.url)}`;
+    if (post.url.isSome()) {
+      params += `&url=${encodeURIComponent(post.url.unwrap())}`;
     }
-    if (post.body) {
+    if (post.body.isSome()) {
       params += `&body=${encodeURIComponent(this.crossPostBody())}`;
     }
     return params;
@@ -1346,9 +1402,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
 
   crossPostBody(): string {
     let post = this.props.post_view.post;
-    let body = `${i18n.t("cross_posted_from")} ${
-      post.ap_id
-    }\n\n${post.body.replace(/^/gm, "> ")}`;
+    let body = `${i18n.t("cross_posted_from")} ${post.ap_id}\n\n${post.body
+      .unwrap()
+      .replace(/^/gm, "> ")}`;
     return body;
   }
 
@@ -1357,12 +1413,13 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   handleModRemoveShow(i: PostListing) {
-    i.state.showRemoveDialog = true;
+    i.state.showRemoveDialog = !i.state.showRemoveDialog;
+    i.state.showBanDialog = false;
     i.setState(i.state);
   }
 
   handleModRemoveReasonChange(i: PostListing, event: any) {
-    i.state.removeReason = event.target.value;
+    i.state.removeReason = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -1373,12 +1430,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
 
   handleModRemoveSubmit(i: PostListing, event: any) {
     event.preventDefault();
-    let form: RemovePost = {
+    let form = new RemovePost({
       post_id: i.props.post_view.post.id,
       removed: !i.props.post_view.post.removed,
       reason: i.state.removeReason,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.removePost(form));
 
     i.state.showRemoveDialog = false;
@@ -1386,42 +1443,86 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   handleModLock(i: PostListing) {
-    let form: LockPost = {
+    let form = new LockPost({
       post_id: i.props.post_view.post.id,
       locked: !i.props.post_view.post.locked,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.lockPost(form));
   }
 
   handleModSticky(i: PostListing) {
-    let form: StickyPost = {
+    let form = new StickyPost({
       post_id: i.props.post_view.post.id,
       stickied: !i.props.post_view.post.stickied,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.stickyPost(form));
   }
 
   handleModBanFromCommunityShow(i: PostListing) {
     i.state.showBanDialog = true;
     i.state.banType = BanType.Community;
+    i.state.showRemoveDialog = false;
     i.setState(i.state);
   }
 
   handleModBanShow(i: PostListing) {
     i.state.showBanDialog = true;
     i.state.banType = BanType.Site;
+    i.state.showRemoveDialog = false;
+    i.setState(i.state);
+  }
+
+  handlePurgePersonShow(i: PostListing) {
+    i.state.showPurgeDialog = true;
+    i.state.purgeType = PurgeType.Person;
+    i.state.showRemoveDialog = false;
+    i.setState(i.state);
+  }
+
+  handlePurgePostShow(i: PostListing) {
+    i.state.showPurgeDialog = true;
+    i.state.purgeType = PurgeType.Post;
+    i.state.showRemoveDialog = false;
+    i.setState(i.state);
+  }
+
+  handlePurgeReasonChange(i: PostListing, event: any) {
+    i.state.purgeReason = Some(event.target.value);
+    i.setState(i.state);
+  }
+
+  handlePurgeSubmit(i: PostListing, event: any) {
+    event.preventDefault();
+
+    if (i.state.purgeType == PurgeType.Person) {
+      let form = new PurgePerson({
+        person_id: i.props.post_view.creator.id,
+        reason: i.state.purgeReason,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(wsClient.purgePerson(form));
+    } else if (i.state.purgeType == PurgeType.Post) {
+      let form = new PurgePost({
+        post_id: i.props.post_view.post.id,
+        reason: i.state.purgeReason,
+        auth: auth().unwrap(),
+      });
+      WebSocketService.Instance.send(wsClient.purgePost(form));
+    }
+
+    i.state.purgeLoading = true;
     i.setState(i.state);
   }
 
   handleModBanReasonChange(i: PostListing, event: any) {
-    i.state.banReason = event.target.value;
+    i.state.banReason = Some(event.target.value);
     i.setState(i.state);
   }
 
-  handleModBanExpiresChange(i: PostListing, event: any) {
-    i.state.banExpires = event.target.value;
+  handleModBanExpireDaysChange(i: PostListing, event: any) {
+    i.state.banExpireDays = Some(event.target.value);
     i.setState(i.state);
   }
 
@@ -1446,15 +1547,15 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
       if (ban == false) {
         i.state.removeData = false;
       }
-      let form: BanFromCommunity = {
+      let form = new BanFromCommunity({
         person_id: i.props.post_view.creator.id,
         community_id: i.props.post_view.community.id,
         ban,
-        remove_data: i.state.removeData,
+        remove_data: Some(i.state.removeData),
         reason: i.state.banReason,
-        expires: getUnixTime(i.state.banExpires),
-        auth: authField(),
-      };
+        expires: i.state.banExpireDays.map(futureDaysToUnixTime),
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(wsClient.banFromCommunity(form));
     } else {
       // If its an unban, restore all their data
@@ -1462,14 +1563,14 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
       if (ban == false) {
         i.state.removeData = false;
       }
-      let form: BanPerson = {
+      let form = new BanPerson({
         person_id: i.props.post_view.creator.id,
         ban,
-        remove_data: i.state.removeData,
+        remove_data: Some(i.state.removeData),
         reason: i.state.banReason,
-        expires: getUnixTime(i.state.banExpires),
-        auth: authField(),
-      };
+        expires: i.state.banExpireDays.map(futureDaysToUnixTime),
+        auth: auth().unwrap(),
+      });
       WebSocketService.Instance.send(wsClient.banPerson(form));
     }
 
@@ -1478,22 +1579,22 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   handleAddModToCommunity(i: PostListing) {
-    let form: AddModToCommunity = {
+    let form = new AddModToCommunity({
       person_id: i.props.post_view.creator.id,
       community_id: i.props.post_view.community.id,
-      added: !i.isMod,
-      auth: authField(),
-    };
+      added: !i.creatorIsMod_,
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.addModToCommunity(form));
     i.setState(i.state);
   }
 
   handleAddAdmin(i: PostListing) {
-    let form: AddAdmin = {
+    let form = new AddAdmin({
       person_id: i.props.post_view.creator.id,
-      added: !i.isAdmin,
-      auth: authField(),
-    };
+      added: !i.creatorIsAdmin_,
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.addAdmin(form));
     i.setState(i.state);
   }
@@ -1509,11 +1610,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   }
 
   handleTransferCommunity(i: PostListing) {
-    let form: TransferCommunity = {
+    let form = new TransferCommunity({
       community_id: i.props.post_view.community.id,
       person_id: i.props.post_view.creator.id,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.transferCommunity(form));
     i.state.showConfirmTransferCommunity = false;
     i.setState(i.state);
@@ -1529,19 +1630,11 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
     i.setState(i.state);
   }
 
-  handleTransferSite(i: PostListing) {
-    let form: TransferSite = {
-      person_id: i.props.post_view.creator.id,
-      auth: authField(),
-    };
-    WebSocketService.Instance.send(wsClient.transferSite(form));
-    i.state.showConfirmTransferSite = false;
-    i.setState(i.state);
-  }
-
-  handleImageExpandClick(i: PostListing) {
+  handleImageExpandClick(i: PostListing, event: any) {
+    event.preventDefault();
     i.state.imageExpanded = !i.state.imageExpanded;
     i.setState(i.state);
+    setupTippy();
   }
 
   handleViewSource(i: PostListing) {
@@ -1571,16 +1664,49 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
   get pointsTippy(): string {
     let points = i18n.t("number_of_points", {
       count: this.state.score,
+      formattedCount: this.state.score,
     });
 
     let upvotes = i18n.t("number_of_upvotes", {
       count: this.state.upvotes,
+      formattedCount: this.state.upvotes,
     });
 
     let downvotes = i18n.t("number_of_downvotes", {
       count: this.state.downvotes,
+      formattedCount: this.state.downvotes,
     });
 
     return `${points} • ${upvotes} • ${downvotes}`;
   }
+
+  get canModOnSelf_(): boolean {
+    return canMod(
+      this.props.moderators,
+      this.props.admins,
+      this.props.post_view.creator.id,
+      undefined,
+      true
+    );
+  }
+
+  get canMod_(): boolean {
+    return canMod(
+      this.props.moderators,
+      this.props.admins,
+      this.props.post_view.creator.id
+    );
+  }
+
+  get canAdmin_(): boolean {
+    return canAdmin(this.props.admins, this.props.post_view.creator.id);
+  }
+
+  get creatorIsMod_(): boolean {
+    return isMod(this.props.moderators, this.props.post_view.creator.id);
+  }
+
+  get creatorIsAdmin_(): boolean {
+    return isAdmin(this.props.admins, this.props.post_view.creator.id);
+  }
 }
index 3dc8260ed871c5c220930e01bc672bb8ac7f7d1b..a26d9d6d4483b3731753d16dcb11e1bfe2f81478 100644 (file)
@@ -1,5 +1,6 @@
+import { None, Some } from "@sniptt/monads";
 import { Component } from "inferno";
-import { T } from "inferno-i18next";
+import { T } from "inferno-i18next-dess";
 import { Link } from "inferno-router";
 import { PostView } from "lemmy-js-client";
 import { i18n } from "../../i18next";
@@ -14,21 +15,29 @@ interface PostListingsProps {
 }
 
 export class PostListings extends Component<PostListingsProps, any> {
-  private duplicatesMap = new Map<number, PostView[]>();
+  duplicatesMap = new Map<number, PostView[]>();
 
   constructor(props: any, context: any) {
     super(props, context);
   }
 
+  get posts() {
+    return this.props.removeDuplicates
+      ? this.removeDuplicates()
+      : this.props.posts;
+  }
+
   render() {
     return (
       <div>
-        {this.props.posts.length > 0 ? (
-          this.outer().map(post_view => (
+        {this.posts.length > 0 ? (
+          this.posts.map(post_view => (
             <>
               <PostListing
                 post_view={post_view}
-                duplicates={this.duplicatesMap.get(post_view.post.id)}
+                duplicates={Some(this.duplicatesMap.get(post_view.post.id))}
+                moderators={None}
+                admins={None}
                 showCommunity={this.props.showCommunity}
                 enableDownvotes={this.props.enableDownvotes}
                 enableNsfw={this.props.enableNsfw}
@@ -39,7 +48,7 @@ export class PostListings extends Component<PostListingsProps, any> {
         ) : (
           <>
             <div>{i18n.t("no_posts")}</div>
-            {this.props.showCommunity !== undefined && (
+            {this.props.showCommunity && (
               <T i18nKey="subscribe_to_communities">
                 #<Link to="/communities">#</Link>
               </T>
@@ -50,34 +59,29 @@ export class PostListings extends Component<PostListingsProps, any> {
     );
   }
 
-  outer(): PostView[] {
-    let out = this.props.posts;
-    if (this.props.removeDuplicates) {
-      out = this.removeDuplicates(out);
-    }
-
-    return out;
-  }
+  removeDuplicates(): PostView[] {
+    // Must use a spread to clone the props, because splice will fail below otherwise.
+    let posts = [...this.props.posts];
 
-  removeDuplicates(posts: PostView[]): PostView[] {
     // A map from post url to list of posts (dupes)
     let urlMap = new Map<string, PostView[]>();
 
     // Loop over the posts, find ones with same urls
     for (let pv of posts) {
-      if (
-        pv.post.url &&
-        !pv.post.deleted &&
+      !pv.post.deleted &&
         !pv.post.removed &&
         !pv.community.deleted &&
-        !pv.community.removed
-      ) {
-        if (!urlMap.get(pv.post.url)) {
-          urlMap.set(pv.post.url, [pv]);
-        } else {
-          urlMap.get(pv.post.url).push(pv);
-        }
-      }
+        !pv.community.removed &&
+        pv.post.url.match({
+          some: url => {
+            if (!urlMap.get(url)) {
+              urlMap.set(url, [pv]);
+            } else {
+              urlMap.get(url).push(pv);
+            }
+          },
+          none: void 0,
+        });
     }
 
     // Sort by oldest
@@ -92,19 +96,22 @@ export class PostListings extends Component<PostListingsProps, any> {
 
     for (let i = 0; i < posts.length; i++) {
       let pv = posts[i];
-      if (pv.post.url) {
-        let found = urlMap.get(pv.post.url);
-        if (found) {
-          // If its the oldest, add
-          if (pv.post.id == found[0].post.id) {
-            this.duplicatesMap.set(pv.post.id, found.slice(1));
+      pv.post.url.match({
+        some: url => {
+          let found = urlMap.get(url);
+          if (found) {
+            // If its the oldest, add
+            if (pv.post.id == found[0].post.id) {
+              this.duplicatesMap.set(pv.post.id, found.slice(1));
+            }
+            // Otherwise, delete it
+            else {
+              posts.splice(i--, 1);
+            }
           }
-          // Otherwise, delete it
-          else {
-            posts.splice(i--, 1);
-          }
-        }
-      }
+        },
+        none: void 0,
+      });
     }
 
     return posts;
diff --git a/src/shared/components/post/post-report.tsx b/src/shared/components/post/post-report.tsx
new file mode 100644 (file)
index 0000000..220a5a9
--- /dev/null
@@ -0,0 +1,111 @@
+import { None } from "@sniptt/monads";
+import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next-dess";
+import {
+  PostReportView,
+  PostView,
+  ResolvePostReport,
+  SubscribedType,
+} from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
+import { auth, wsClient } from "../../utils";
+import { Icon } from "../common/icon";
+import { PersonListing } from "../person/person-listing";
+import { PostListing } from "./post-listing";
+
+interface PostReportProps {
+  report: PostReportView;
+}
+
+export class PostReport extends Component<PostReportProps, any> {
+  constructor(props: any, context: any) {
+    super(props, context);
+  }
+
+  render() {
+    let r = this.props.report;
+    let post = r.post;
+    let tippyContent = i18n.t(
+      r.post_report.resolved ? "unresolve_report" : "resolve_report"
+    );
+
+    // Set the original post data ( a troll could change it )
+    post.name = r.post_report.original_post_name;
+    post.url = r.post_report.original_post_url;
+    post.body = r.post_report.original_post_body;
+    let pv: PostView = {
+      post,
+      creator: r.post_creator,
+      community: r.community,
+      creator_banned_from_community: r.creator_banned_from_community,
+      counts: r.counts,
+      subscribed: SubscribedType.NotSubscribed,
+      saved: false,
+      read: false,
+      creator_blocked: false,
+      my_vote: r.my_vote,
+    };
+
+    return (
+      <div>
+        <PostListing
+          post_view={pv}
+          duplicates={None}
+          moderators={None}
+          admins={None}
+          showCommunity={true}
+          enableDownvotes={true}
+          enableNsfw={true}
+          viewOnly={true}
+        />
+        <div>
+          {i18n.t("reporter")}: <PersonListing person={r.creator} />
+        </div>
+        <div>
+          {i18n.t("reason")}: {r.post_report.reason}
+        </div>
+        {r.resolver.match({
+          some: resolver => (
+            <div>
+              {r.post_report.resolved ? (
+                <T i18nKey="resolved_by">
+                  #
+                  <PersonListing person={resolver} />
+                </T>
+              ) : (
+                <T i18nKey="unresolved_by">
+                  #
+                  <PersonListing person={resolver} />
+                </T>
+              )}
+            </div>
+          ),
+          none: <></>,
+        })}
+        <button
+          className="btn btn-link btn-animate text-muted py-0"
+          onClick={linkEvent(this, this.handleResolveReport)}
+          data-tippy-content={tippyContent}
+          aria-label={tippyContent}
+        >
+          <Icon
+            icon="check"
+            classes={`icon-inline ${
+              r.post_report.resolved ? "text-success" : "text-danger"
+            }`}
+          />
+        </button>
+      </div>
+    );
+  }
+
+  handleResolveReport(i: PostReport) {
+    let form = new ResolvePostReport({
+      report_id: i.props.report.post_report.id,
+      resolved: !i.props.report.post_report.resolved,
+      auth: auth().unwrap(),
+    });
+    WebSocketService.Instance.send(wsClient.resolvePostReport(form));
+  }
+}
index 3186242a970c58fa7705822f8874fdc24bb9459f..58cf71e8158150850fef8eef730f8733e5686081 100644 (file)
@@ -1,3 +1,4 @@
+import { None, Option, Right, Some } from "@sniptt/monads";
 import autosize from "autosize";
 import { Component, createRef, linkEvent, RefObject } from "inferno";
 import {
@@ -6,56 +7,63 @@ import {
   BanFromCommunityResponse,
   BanPersonResponse,
   BlockPersonResponse,
+  CommentNode as CommentNodeI,
+  CommentReportResponse,
   CommentResponse,
+  CommentSortType,
   CommunityResponse,
+  GetComments,
+  GetCommentsResponse,
   GetCommunityResponse,
   GetPost,
   GetPostResponse,
   GetSiteResponse,
   ListingType,
-  MarkCommentAsRead,
+  PostReportResponse,
   PostResponse,
   PostView,
+  PurgeItemResponse,
   Search,
   SearchResponse,
   SearchType,
   SortType,
+  toOption,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
-import {
-  CommentNode as CommentNodeI,
-  CommentSortType,
-  CommentViewType,
-  InitialFetchRequest,
-} from "../../interfaces";
+import { CommentViewType, InitialFetchRequest } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   buildCommentsTree,
   commentsToFlatNodes,
+  commentTreeMaxDepth,
   createCommentLikeRes,
   createPostLikeRes,
+  debounce,
   editCommentRes,
+  enableDownvotes,
+  enableNsfw,
   getCommentIdFromProps,
+  getCommentParentId,
+  getDepthFromComment,
   getIdFromProps,
   insertCommentIntoTree,
   isBrowser,
   isImage,
-  previewLines,
   restoreScrollPosition,
   saveCommentRes,
   saveScrollPosition,
   setIsoData,
-  setOptionalAuth,
   setupTippy,
   toast,
+  trendingFetchLimit,
   updatePersonBlock,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { CommentForm } from "../comment/comment-form";
 import { CommentNodes } from "../comment/comment-nodes";
@@ -64,37 +72,48 @@ import { Icon, Spinner } from "../common/icon";
 import { Sidebar } from "../community/sidebar";
 import { PostListing } from "./post-listing";
 
+const commentsShownInterval = 15;
+
 interface PostState {
-  postRes: GetPostResponse;
-  postId: number;
+  postId: Option<number>;
+  commentId: Option<number>;
+  postRes: Option<GetPostResponse>;
+  commentsRes: Option<GetCommentsResponse>;
   commentTree: CommentNodeI[];
-  commentId?: number;
   commentSort: CommentSortType;
   commentViewType: CommentViewType;
   scrolled?: boolean;
   loading: boolean;
-  crossPosts: PostView[];
+  crossPosts: Option<PostView[]>;
   siteRes: GetSiteResponse;
   commentSectionRef?: RefObject<HTMLDivElement>;
   showSidebarMobile: boolean;
+  maxCommentsShown: number;
 }
 
 export class Post extends Component<any, PostState> {
   private subscription: Subscription;
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(
+    this.context,
+    GetPostResponse,
+    GetCommentsResponse
+  );
+  private commentScrollDebounced: () => void;
   private emptyState: PostState = {
-    postRes: null,
+    postRes: None,
+    commentsRes: None,
     postId: getIdFromProps(this.props),
-    commentTree: [],
     commentId: getCommentIdFromProps(this.props),
-    commentSort: CommentSortType.Hot,
+    commentTree: [],
+    commentSort: CommentSortType[CommentSortType.Hot],
     commentViewType: CommentViewType.Tree,
     scrolled: false,
     loading: true,
-    crossPosts: [],
+    crossPosts: None,
     siteRes: this.isoData.site_res,
     commentSectionRef: null,
     showSidebarMobile: false,
+    maxCommentsShown: commentsShownInterval,
   };
 
   constructor(props: any, context: any) {
@@ -108,18 +127,37 @@ export class Post extends Component<any, PostState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.postRes = this.isoData.routeData[0];
-      this.state.commentTree = buildCommentsTree(
-        this.state.postRes.comments,
-        this.state.commentSort
+      this.state.postRes = Some(this.isoData.routeData[0] as GetPostResponse);
+      this.state.commentsRes = Some(
+        this.isoData.routeData[1] as GetCommentsResponse
       );
+
+      this.state.commentsRes.match({
+        some: res => {
+          this.state.commentTree = buildCommentsTree(
+            res.comments,
+            this.state.commentId.isSome()
+          );
+        },
+        none: void 0,
+      });
       this.state.loading = false;
 
       if (isBrowser()) {
+        WebSocketService.Instance.send(
+          wsClient.communityJoin({
+            community_id:
+              this.state.postRes.unwrap().community_view.community.id,
+          })
+        );
+
+        this.state.postId.match({
+          some: post_id =>
+            WebSocketService.Instance.send(wsClient.postJoin({ post_id })),
+          none: void 0,
+        });
+
         this.fetchCrossPosts();
-        if (this.state.commentId) {
-          this.scrollCommentIntoView();
-        }
 
         if (this.checkScrollIntoCommentsParam) {
           this.scrollIntoCommentSection();
@@ -131,71 +169,110 @@ export class Post extends Component<any, PostState> {
   }
 
   fetchPost() {
-    let form: GetPost = {
+    this.setState({ commentsRes: None });
+    let postForm = new GetPost({
       id: this.state.postId,
-      auth: authField(false),
-    };
-    WebSocketService.Instance.send(wsClient.getPost(form));
+      comment_id: this.state.commentId,
+      auth: auth(false).ok(),
+    });
+    WebSocketService.Instance.send(wsClient.getPost(postForm));
+
+    let commentsForm = new GetComments({
+      post_id: this.state.postId,
+      parent_id: this.state.commentId,
+      max_depth: Some(commentTreeMaxDepth),
+      page: None,
+      limit: None,
+      sort: Some(this.state.commentSort),
+      type_: Some(ListingType.All),
+      community_name: None,
+      community_id: None,
+      saved_only: Some(false),
+      auth: auth(false).ok(),
+    });
+    WebSocketService.Instance.send(wsClient.getComments(commentsForm));
   }
 
   fetchCrossPosts() {
-    if (this.state.postRes.post_view.post.url) {
-      let form: Search = {
-        q: this.state.postRes.post_view.post.url,
-        type_: SearchType.Url,
-        sort: SortType.TopAll,
-        listing_type: ListingType.All,
-        page: 1,
-        limit: 6,
-        auth: authField(false),
-      };
-      WebSocketService.Instance.send(wsClient.search(form));
-    }
+    this.state.postRes
+      .andThen(r => r.post_view.post.url)
+      .match({
+        some: url => {
+          let form = new Search({
+            q: url,
+            type_: Some(SearchType.Url),
+            sort: Some(SortType.TopAll),
+            listing_type: Some(ListingType.All),
+            page: Some(1),
+            limit: Some(trendingFetchLimit),
+            community_id: None,
+            community_name: None,
+            creator_id: None,
+            auth: auth(false).ok(),
+          });
+          WebSocketService.Instance.send(wsClient.search(form));
+        },
+        none: void 0,
+      });
   }
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
     let pathSplit = req.path.split("/");
     let promises: Promise<any>[] = [];
 
+    let pathType = pathSplit[1];
     let id = Number(pathSplit[2]);
 
-    let postForm: GetPost = {
-      id,
-    };
-    setOptionalAuth(postForm, req.auth);
+    let postForm = new GetPost({
+      id: None,
+      comment_id: None,
+      auth: req.auth,
+    });
+
+    let commentsForm = new GetComments({
+      post_id: None,
+      parent_id: None,
+      max_depth: Some(commentTreeMaxDepth),
+      page: None,
+      limit: None,
+      sort: Some(CommentSortType.Hot),
+      type_: Some(ListingType.All),
+      community_name: None,
+      community_id: None,
+      saved_only: Some(false),
+      auth: req.auth,
+    });
+
+    // Set the correct id based on the path type
+    if (pathType == "post") {
+      postForm.id = Some(id);
+      commentsForm.post_id = Some(id);
+    } else {
+      postForm.comment_id = Some(id);
+      commentsForm.parent_id = Some(id);
+    }
 
     promises.push(req.client.getPost(postForm));
+    promises.push(req.client.getComments(commentsForm));
 
     return promises;
   }
 
   componentWillUnmount() {
     this.subscription.unsubscribe();
-    window.isoData.path = undefined;
+    document.removeEventListener("scroll", this.commentScrollDebounced);
+
     saveScrollPosition(this.context);
   }
 
   componentDidMount() {
-    WebSocketService.Instance.send(
-      wsClient.postJoin({ post_id: this.state.postId })
-    );
     autosize(document.querySelectorAll("textarea"));
-  }
-
-  componentDidUpdate(_lastProps: any, lastState: PostState) {
-    if (
-      this.state.commentId &&
-      !this.state.scrolled &&
-      lastState.postRes &&
-      lastState.postRes.comments.length > 0
-    ) {
-      this.scrollCommentIntoView();
-    }
 
-    if (this.checkScrollIntoCommentsParam) {
-      this.scrollIntoCommentSection();
-    }
+    this.commentScrollDebounced = debounce(this.trackCommentsBoxScrolling, 100);
+    document.addEventListener("scroll", this.commentScrollDebounced);
+  }
 
+  componentDidUpdate(_lastProps: any) {
     // Necessary if you are on a post and you click another post (same route)
     if (_lastProps.location.pathname !== _lastProps.history.location.pathname) {
       // TODO Couldnt get a refresh working. This does for now.
@@ -208,14 +285,6 @@ export class Post extends Component<any, PostState> {
     }
   }
 
-  scrollCommentIntoView() {
-    var elmnt = document.getElementById(`comment-${this.state.commentId}`);
-    elmnt.scrollIntoView();
-    elmnt.classList.add("mark");
-    this.state.scrolled = true;
-    this.markScrolledAsRead(this.state.commentId);
-  }
-
   get checkScrollIntoCommentsParam() {
     return Boolean(
       new URLSearchParams(this.props.location.search).get("scrollToComments")
@@ -226,54 +295,51 @@ export class Post extends Component<any, PostState> {
     this.state.commentSectionRef.current?.scrollIntoView();
   }
 
-  // TODO this needs some re-work
-  markScrolledAsRead(commentId: number) {
-    let found = this.state.postRes.comments.find(
-      c => c.comment.id == commentId
-    );
-    let parent = this.state.postRes.comments.find(
-      c => found.comment.parent_id == c.comment.id
-    );
-    let parent_person_id = parent
-      ? parent.creator.id
-      : this.state.postRes.post_view.creator.id;
-
-    if (
-      UserService.Instance.myUserInfo &&
-      UserService.Instance.myUserInfo.local_user_view.person.id ==
-        parent_person_id
-    ) {
-      let form: MarkCommentAsRead = {
-        comment_id: found.comment.id,
-        read: true,
-        auth: authField(),
-      };
-      WebSocketService.Instance.send(wsClient.markCommentAsRead(form));
-      UserService.Instance.unreadCountSub.next(
-        UserService.Instance.unreadCountSub.value - 1
-      );
-    }
+  isBottom(el: Element): boolean {
+    return el?.getBoundingClientRect().bottom <= window.innerHeight;
   }
 
+  /**
+   * Shows new comments when scrolling to the bottom of the comments div
+   */
+  trackCommentsBoxScrolling = () => {
+    const wrappedElement = document.getElementsByClassName("comments")[0];
+    if (wrappedElement && this.isBottom(wrappedElement)) {
+      this.state.maxCommentsShown += commentsShownInterval;
+      this.setState(this.state);
+    }
+  };
+
   get documentTitle(): string {
-    return `${this.state.postRes.post_view.post.name} - ${this.state.siteRes.site_view.site.name}`;
+    return this.state.postRes.match({
+      some: res =>
+        this.state.siteRes.site_view.match({
+          some: siteView =>
+            `${res.post_view.post.name} - ${siteView.site.name}`,
+          none: "",
+        }),
+      none: "",
+    });
   }
 
-  get imageTag(): string {
-    let post = this.state.postRes.post_view.post;
-    return (
-      post.thumbnail_url ||
-      (post.url ? (isImage(post.url) ? post.url : undefined) : undefined)
-    );
+  get imageTag(): Option<string> {
+    return this.state.postRes.match({
+      some: res =>
+        res.post_view.post.thumbnail_url.or(
+          res.post_view.post.url.match({
+            some: url => (isImage(url) ? Some(url) : None),
+            none: None,
+          })
+        ),
+      none: None,
+    });
   }
 
-  get descriptionTag(): string {
-    let body = this.state.postRes.post_view.post.body;
-    return body ? previewLines(body) : undefined;
+  get descriptionTag(): Option<string> {
+    return this.state.postRes.andThen(r => r.post_view.post.body);
   }
 
   render() {
-    let pv = this.state.postRes?.post_view;
     return (
       <div class="container">
         {this.state.loading ? (
@@ -281,56 +347,59 @@ export class Post extends Component<any, PostState> {
             <Spinner large />
           </h5>
         ) : (
-          <div class="row">
-            <div class="col-12 col-md-8 mb-3">
-              <HtmlTags
-                title={this.documentTitle}
-                path={this.context.router.route.match.url}
-                image={this.imageTag}
-                description={this.descriptionTag}
-              />
-              <PostListing
-                post_view={pv}
-                duplicates={this.state.crossPosts}
-                showBody
-                showCommunity
-                moderators={this.state.postRes.moderators}
-                admins={this.state.siteRes.admins}
-                enableDownvotes={
-                  this.state.siteRes.site_view.site.enable_downvotes
-                }
-                enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
-              />
-              <div ref={this.state.commentSectionRef} className="mb-2" />
-              <CommentForm
-                postId={this.state.postId}
-                disabled={pv.post.locked}
-              />
-              <div class="d-block d-md-none">
-                <button
-                  class="btn btn-secondary d-inline-block mb-2 mr-3"
-                  onClick={linkEvent(this, this.handleShowSidebarMobile)}
-                >
-                  {i18n.t("sidebar")}{" "}
-                  <Icon
-                    icon={
-                      this.state.showSidebarMobile
-                        ? `minus-square`
-                        : `plus-square`
-                    }
-                    classes="icon-inline"
+          this.state.postRes.match({
+            some: res => (
+              <div class="row">
+                <div class="col-12 col-md-8 mb-3">
+                  <HtmlTags
+                    title={this.documentTitle}
+                    path={this.context.router.route.match.url}
+                    image={this.imageTag}
+                    description={this.descriptionTag}
                   />
-                </button>
-                {this.state.showSidebarMobile && this.sidebar()}
+                  <PostListing
+                    post_view={res.post_view}
+                    duplicates={this.state.crossPosts}
+                    showBody
+                    showCommunity
+                    moderators={Some(res.moderators)}
+                    admins={Some(this.state.siteRes.admins)}
+                    enableDownvotes={enableDownvotes(this.state.siteRes)}
+                    enableNsfw={enableNsfw(this.state.siteRes)}
+                  />
+                  <div ref={this.state.commentSectionRef} className="mb-2" />
+                  <CommentForm
+                    node={Right(res.post_view.post.id)}
+                    disabled={res.post_view.post.locked}
+                  />
+                  <div class="d-block d-md-none">
+                    <button
+                      class="btn btn-secondary d-inline-block mb-2 mr-3"
+                      onClick={linkEvent(this, this.handleShowSidebarMobile)}
+                    >
+                      {i18n.t("sidebar")}{" "}
+                      <Icon
+                        icon={
+                          this.state.showSidebarMobile
+                            ? `minus-square`
+                            : `plus-square`
+                        }
+                        classes="icon-inline"
+                      />
+                    </button>
+                    {this.state.showSidebarMobile && this.sidebar()}
+                  </div>
+                  {this.sortRadios()}
+                  {this.state.commentViewType == CommentViewType.Tree &&
+                    this.commentsTree()}
+                  {this.state.commentViewType == CommentViewType.Flat &&
+                    this.commentsFlat()}
+                </div>
+                <div class="d-none d-md-block col-md-4">{this.sidebar()}</div>
               </div>
-              {this.state.postRes.comments.length > 0 && this.sortRadios()}
-              {this.state.commentViewType == CommentViewType.Tree &&
-                this.commentsTree()}
-              {this.state.commentViewType == CommentViewType.Chat &&
-                this.commentsFlat()}
-            </div>
-            <div class="d-none d-md-block col-md-4">{this.sidebar()}</div>
-          </div>
+            ),
+            none: <></>,
+          })
         )}
       </div>
     );
@@ -342,7 +411,8 @@ export class Post extends Component<any, PostState> {
         <div class="btn-group btn-group-toggle flex-wrap mr-3 mb-2">
           <label
             className={`btn btn-outline-secondary pointer ${
-              this.state.commentSort === CommentSortType.Hot && "active"
+              CommentSortType[this.state.commentSort] === CommentSortType.Hot &&
+              "active"
             }`}
           >
             {i18n.t("hot")}
@@ -355,7 +425,8 @@ export class Post extends Component<any, PostState> {
           </label>
           <label
             className={`btn btn-outline-secondary pointer ${
-              this.state.commentSort === CommentSortType.Top && "active"
+              CommentSortType[this.state.commentSort] === CommentSortType.Top &&
+              "active"
             }`}
           >
             {i18n.t("top")}
@@ -368,7 +439,8 @@ export class Post extends Component<any, PostState> {
           </label>
           <label
             className={`btn btn-outline-secondary pointer ${
-              this.state.commentSort === CommentSortType.New && "active"
+              CommentSortType[this.state.commentSort] === CommentSortType.New &&
+              "active"
             }`}
           >
             {i18n.t("new")}
@@ -381,7 +453,8 @@ export class Post extends Component<any, PostState> {
           </label>
           <label
             className={`btn btn-outline-secondary pointer ${
-              this.state.commentSort === CommentSortType.Old && "active"
+              CommentSortType[this.state.commentSort] === CommentSortType.Old &&
+              "active"
             }`}
           >
             {i18n.t("old")}
@@ -396,14 +469,14 @@ export class Post extends Component<any, PostState> {
         <div class="btn-group btn-group-toggle flex-wrap mb-2">
           <label
             className={`btn btn-outline-secondary pointer ${
-              this.state.commentViewType === CommentViewType.Chat && "active"
+              this.state.commentViewType === CommentViewType.Flat && "active"
             }`}
           >
             {i18n.t("chat")}
             <input
               type="radio"
-              value={CommentViewType.Chat}
-              checked={this.state.commentViewType === CommentViewType.Chat}
+              value={CommentViewType.Flat}
+              checked={this.state.commentViewType === CommentViewType.Flat}
               onChange={linkEvent(this, this.handleCommentViewTypeChange)}
             />
           </label>
@@ -414,53 +487,61 @@ export class Post extends Component<any, PostState> {
 
   commentsFlat() {
     // These are already sorted by new
-    return (
-      <div>
-        <CommentNodes
-          nodes={commentsToFlatNodes(this.state.postRes.comments)}
-          noIndent
-          locked={this.state.postRes.post_view.post.locked}
-          moderators={this.state.postRes.moderators}
-          admins={this.state.siteRes.admins}
-          postCreatorId={this.state.postRes.post_view.creator.id}
-          showContext
-          enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes}
-        />
-      </div>
-    );
+    return this.state.commentsRes.match({
+      some: commentsRes =>
+        this.state.postRes.match({
+          some: postRes => (
+            <div>
+              <CommentNodes
+                nodes={commentsToFlatNodes(commentsRes.comments)}
+                viewType={this.state.commentViewType}
+                maxCommentsShown={Some(this.state.maxCommentsShown)}
+                noIndent
+                locked={postRes.post_view.post.locked}
+                moderators={Some(postRes.moderators)}
+                admins={Some(this.state.siteRes.admins)}
+                enableDownvotes={enableDownvotes(this.state.siteRes)}
+                showContext
+              />
+            </div>
+          ),
+          none: <></>,
+        }),
+      none: <></>,
+    });
   }
 
   sidebar() {
-    return (
-      <div class="mb-3">
-        <Sidebar
-          community_view={this.state.postRes.community_view}
-          moderators={this.state.postRes.moderators}
-          admins={this.state.siteRes.admins}
-          online={this.state.postRes.online}
-          enableNsfw={this.state.siteRes.site_view.site.enable_nsfw}
-          showIcon
-        />
-      </div>
-    );
+    return this.state.postRes.match({
+      some: res => (
+        <div class="mb-3">
+          <Sidebar
+            community_view={res.community_view}
+            moderators={res.moderators}
+            admins={this.state.siteRes.admins}
+            online={res.online}
+            enableNsfw={enableNsfw(this.state.siteRes)}
+            showIcon
+          />
+        </div>
+      ),
+      none: <></>,
+    });
   }
 
   handleCommentSortChange(i: Post, event: any) {
-    i.state.commentSort = Number(event.target.value);
+    i.state.commentSort = CommentSortType[event.target.value];
     i.state.commentViewType = CommentViewType.Tree;
-    i.state.commentTree = buildCommentsTree(
-      i.state.postRes.comments,
-      i.state.commentSort
-    );
     i.setState(i.state);
+    i.fetchPost();
   }
 
   handleCommentViewTypeChange(i: Post, event: any) {
     i.state.commentViewType = Number(event.target.value);
     i.state.commentSort = CommentSortType.New;
     i.state.commentTree = buildCommentsTree(
-      i.state.postRes.comments,
-      i.state.commentSort
+      i.state.commentsRes.map(r => r.comments).unwrapOr([]),
+      i.state.commentId.isSome()
     );
     i.setState(i.state);
   }
@@ -470,19 +551,64 @@ export class Post extends Component<any, PostState> {
     i.setState(i.state);
   }
 
+  handleViewPost(i: Post) {
+    i.state.postRes.match({
+      some: res =>
+        i.context.router.history.push(`/post/${res.post_view.post.id}`),
+      none: void 0,
+    });
+  }
+
+  handleViewContext(i: Post) {
+    i.state.commentsRes.match({
+      some: res =>
+        i.context.router.history.push(
+          `/comment/${getCommentParentId(res.comments[0].comment).unwrap()}`
+        ),
+      none: void 0,
+    });
+  }
+
   commentsTree() {
-    return (
-      <div>
-        <CommentNodes
-          nodes={this.state.commentTree}
-          locked={this.state.postRes.post_view.post.locked}
-          moderators={this.state.postRes.moderators}
-          admins={this.state.siteRes.admins}
-          postCreatorId={this.state.postRes.post_view.creator.id}
-          enableDownvotes={this.state.siteRes.site_view.site.enable_downvotes}
-        />
-      </div>
-    );
+    let showContextButton = toOption(this.state.commentTree[0]).match({
+      some: comment => getDepthFromComment(comment.comment_view.comment) > 0,
+      none: false,
+    });
+
+    return this.state.postRes.match({
+      some: res => (
+        <div>
+          {this.state.commentId.isSome() && (
+            <>
+              <button
+                class="pl-0 d-block btn btn-link text-muted"
+                onClick={linkEvent(this, this.handleViewPost)}
+              >
+                {i18n.t("view_all_comments")} ➔
+              </button>
+              {showContextButton && (
+                <button
+                  class="pl-0 d-block btn btn-link text-muted"
+                  onClick={linkEvent(this, this.handleViewContext)}
+                >
+                  {i18n.t("show_context")} ➔
+                </button>
+              )}
+            </>
+          )}
+          <CommentNodes
+            nodes={this.state.commentTree}
+            viewType={this.state.commentViewType}
+            maxCommentsShown={Some(this.state.maxCommentsShown)}
+            locked={res.post_view.post.locked}
+            moderators={Some(res.moderators)}
+            admins={Some(this.state.siteRes.admins)}
+            enableDownvotes={enableDownvotes(this.state.siteRes)}
+          />
+        </div>
+      ),
+      none: <></>,
+    });
   }
 
   parseMessage(msg: any) {
@@ -492,40 +618,95 @@ export class Post extends Component<any, PostState> {
       toast(i18n.t(msg.error), "danger");
       return;
     } else if (msg.reconnect) {
-      let postId = Number(this.props.match.params.id);
-      WebSocketService.Instance.send(wsClient.postJoin({ post_id: postId }));
+      this.state.postRes.match({
+        some: res => {
+          let postId = res.post_view.post.id;
+          WebSocketService.Instance.send(
+            wsClient.postJoin({ post_id: postId })
+          );
+          WebSocketService.Instance.send(
+            wsClient.getPost({
+              id: Some(postId),
+              comment_id: None,
+              auth: auth(false).ok(),
+            })
+          );
+        },
+        none: void 0,
+      });
+    } else if (op == UserOperation.GetPost) {
+      let data = wsJsonToRes<GetPostResponse>(msg, GetPostResponse);
+      this.state.postRes = Some(data);
+
+      // join the rooms
       WebSocketService.Instance.send(
-        wsClient.getPost({
-          id: postId,
-          auth: authField(false),
-        })
+        wsClient.postJoin({ post_id: data.post_view.post.id })
       );
-    } else if (op == UserOperation.GetPost) {
-      let data = wsJsonToRes<GetPostResponse>(msg).data;
-      this.state.postRes = data;
-      this.state.commentTree = buildCommentsTree(
-        this.state.postRes.comments,
-        this.state.commentSort
+      WebSocketService.Instance.send(
+        wsClient.communityJoin({
+          community_id: data.community_view.community.id,
+        })
       );
-      this.state.loading = false;
 
       // Get cross-posts
+      // TODO move this into initial fetch and refetch
       this.fetchCrossPosts();
       this.setState(this.state);
       setupTippy();
-      if (!this.state.commentId) restoreScrollPosition(this.context);
+      if (this.state.commentId.isNone()) restoreScrollPosition(this.context);
 
       if (this.checkScrollIntoCommentsParam) {
         this.scrollIntoCommentSection();
       }
+    } else if (op == UserOperation.GetComments) {
+      let data = wsJsonToRes<GetCommentsResponse>(msg, GetCommentsResponse);
+      // You might need to append here, since this could be building more comments from a tree fetch
+      this.state.commentsRes.match({
+        some: res => {
+          // Remove the first comment, since it is the parent
+          let newComments = data.comments;
+          newComments.shift();
+          res.comments.push(...newComments);
+        },
+        none: () => {
+          this.state.commentsRes = Some(data);
+        },
+      });
+      // this.state.commentsRes = Some(data);
+      this.state.commentTree = buildCommentsTree(
+        this.state.commentsRes.map(r => r.comments).unwrapOr([]),
+        this.state.commentId.isSome()
+      );
+      this.state.loading = false;
+      this.setState(this.state);
     } else if (op == UserOperation.CreateComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+
+      // Don't get comments from the post room, if the creator is blocked
+      let creatorBlocked = UserService.Instance.myUserInfo
+        .map(m => m.person_blocks)
+        .unwrapOr([])
+        .map(pb => pb.target.id)
+        .includes(data.comment_view.creator.id);
 
       // Necessary since it might be a user reply, which has the recipients, to avoid double
-      if (data.recipient_ids.length == 0) {
-        this.state.postRes.comments.unshift(data.comment_view);
-        insertCommentIntoTree(this.state.commentTree, data.comment_view);
-        this.state.postRes.post_view.counts.comments++;
+      if (data.recipient_ids.length == 0 && !creatorBlocked) {
+        this.state.postRes.match({
+          some: postRes =>
+            this.state.commentsRes.match({
+              some: commentsRes => {
+                commentsRes.comments.unshift(data.comment_view);
+                insertCommentIntoTree(
+                  this.state.commentTree,
+                  data.comment_view,
+                  this.state.commentId.isSome()
+                );
+                postRes.post_view.counts.comments++;
+              },
+              none: void 0,
+            }),
+          none: void 0,
+        });
         this.setState(this.state);
         setupTippy();
       }
@@ -534,21 +715,34 @@ export class Post extends Component<any, PostState> {
       op == UserOperation.DeleteComment ||
       op == UserOperation.RemoveComment
     ) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      editCommentRes(data.comment_view, this.state.postRes.comments);
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      editCommentRes(
+        data.comment_view,
+        this.state.commentsRes.map(r => r.comments).unwrapOr([])
+      );
       this.setState(this.state);
+      setupTippy();
     } else if (op == UserOperation.SaveComment) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      saveCommentRes(data.comment_view, this.state.postRes.comments);
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      saveCommentRes(
+        data.comment_view,
+        this.state.commentsRes.map(r => r.comments).unwrapOr([])
+      );
       this.setState(this.state);
       setupTippy();
     } else if (op == UserOperation.CreateCommentLike) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
-      createCommentLikeRes(data.comment_view, this.state.postRes.comments);
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
+      createCommentLikeRes(
+        data.comment_view,
+        this.state.commentsRes.map(r => r.comments).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (op == UserOperation.CreatePostLike) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      createPostLikeRes(data.post_view, this.state.postRes.post_view);
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      this.state.postRes.match({
+        some: res => createPostLikeRes(data.post_view, res.post_view),
+        none: void 0,
+      });
       this.setState(this.state);
     } else if (
       op == UserOperation.EditPost ||
@@ -558,8 +752,11 @@ export class Post extends Component<any, PostState> {
       op == UserOperation.StickyPost ||
       op == UserOperation.SavePost
     ) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      this.state.postRes.post_view = data.post_view;
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      this.state.postRes.match({
+        some: res => (res.post_view = data.post_view),
+        none: void 0,
+      });
       this.setState(this.state);
       setupTippy();
     } else if (
@@ -568,61 +765,116 @@ export class Post extends Component<any, PostState> {
       op == UserOperation.RemoveCommunity ||
       op == UserOperation.FollowCommunity
     ) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
-      this.state.postRes.community_view = data.community_view;
-      this.state.postRes.post_view.community = data.community_view.community;
-      this.setState(this.state);
-      this.setState(this.state);
+      let data = wsJsonToRes<CommunityResponse>(msg, CommunityResponse);
+      this.state.postRes.match({
+        some: res => {
+          res.community_view = data.community_view;
+          res.post_view.community = data.community_view.community;
+          this.setState(this.state);
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.BanFromCommunity) {
-      let data = wsJsonToRes<BanFromCommunityResponse>(msg).data;
-      this.state.postRes.comments
-        .filter(c => c.creator.id == data.person_view.person.id)
-        .forEach(c => (c.creator_banned_from_community = data.banned));
-      if (
-        this.state.postRes.post_view.creator.id == data.person_view.person.id
-      ) {
-        this.state.postRes.post_view.creator_banned_from_community =
-          data.banned;
-      }
-      this.setState(this.state);
+      let data = wsJsonToRes<BanFromCommunityResponse>(
+        msg,
+        BanFromCommunityResponse
+      );
+      this.state.postRes.match({
+        some: postRes =>
+          this.state.commentsRes.match({
+            some: commentsRes => {
+              commentsRes.comments
+                .filter(c => c.creator.id == data.person_view.person.id)
+                .forEach(c => (c.creator_banned_from_community = data.banned));
+              if (postRes.post_view.creator.id == data.person_view.person.id) {
+                postRes.post_view.creator_banned_from_community = data.banned;
+              }
+              this.setState(this.state);
+            },
+            none: void 0,
+          }),
+        none: void 0,
+      });
     } else if (op == UserOperation.AddModToCommunity) {
-      let data = wsJsonToRes<AddModToCommunityResponse>(msg).data;
-      this.state.postRes.moderators = data.moderators;
-      this.setState(this.state);
+      let data = wsJsonToRes<AddModToCommunityResponse>(
+        msg,
+        AddModToCommunityResponse
+      );
+      this.state.postRes.match({
+        some: res => {
+          res.moderators = data.moderators;
+          this.setState(this.state);
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.BanPerson) {
-      let data = wsJsonToRes<BanPersonResponse>(msg).data;
-      this.state.postRes.comments
-        .filter(c => c.creator.id == data.person_view.person.id)
-        .forEach(c => (c.creator.banned = data.banned));
-      if (
-        this.state.postRes.post_view.creator.id == data.person_view.person.id
-      ) {
-        this.state.postRes.post_view.creator.banned = data.banned;
-      }
-      this.setState(this.state);
+      let data = wsJsonToRes<BanPersonResponse>(msg, BanPersonResponse);
+      this.state.postRes.match({
+        some: postRes =>
+          this.state.commentsRes.match({
+            some: commentsRes => {
+              commentsRes.comments
+                .filter(c => c.creator.id == data.person_view.person.id)
+                .forEach(c => (c.creator.banned = data.banned));
+              if (postRes.post_view.creator.id == data.person_view.person.id) {
+                postRes.post_view.creator.banned = data.banned;
+              }
+              this.setState(this.state);
+            },
+            none: void 0,
+          }),
+        none: void 0,
+      });
     } else if (op == UserOperation.AddAdmin) {
-      let data = wsJsonToRes<AddAdminResponse>(msg).data;
+      let data = wsJsonToRes<AddAdminResponse>(msg, AddAdminResponse);
       this.state.siteRes.admins = data.admins;
       this.setState(this.state);
     } else if (op == UserOperation.Search) {
-      let data = wsJsonToRes<SearchResponse>(msg).data;
-      this.state.crossPosts = data.posts.filter(
+      let data = wsJsonToRes<SearchResponse>(msg, SearchResponse);
+      let xPosts = data.posts.filter(
         p => p.post.id != Number(this.props.match.params.id)
       );
+      this.state.crossPosts = xPosts.length > 0 ? Some(xPosts) : None;
       this.setState(this.state);
-    } else if (op == UserOperation.TransferSite) {
-      let data = wsJsonToRes<GetSiteResponse>(msg).data;
+    } else if (op == UserOperation.LeaveAdmin) {
+      let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
       this.state.siteRes = data;
       this.setState(this.state);
     } else if (op == UserOperation.TransferCommunity) {
-      let data = wsJsonToRes<GetCommunityResponse>(msg).data;
-      this.state.postRes.community_view = data.community_view;
-      this.state.postRes.post_view.community = data.community_view.community;
-      this.state.postRes.moderators = data.moderators;
-      this.setState(this.state);
+      let data = wsJsonToRes<GetCommunityResponse>(msg, GetCommunityResponse);
+      this.state.postRes.match({
+        some: res => {
+          res.community_view = data.community_view;
+          res.post_view.community = data.community_view.community;
+          res.moderators = data.moderators;
+          this.setState(this.state);
+        },
+        none: void 0,
+      });
     } else if (op == UserOperation.BlockPerson) {
-      let data = wsJsonToRes<BlockPersonResponse>(msg).data;
+      let data = wsJsonToRes<BlockPersonResponse>(msg, BlockPersonResponse);
       updatePersonBlock(data);
+    } else if (op == UserOperation.CreatePostReport) {
+      let data = wsJsonToRes<PostReportResponse>(msg, PostReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (op == UserOperation.CreateCommentReport) {
+      let data = wsJsonToRes<CommentReportResponse>(msg, CommentReportResponse);
+      if (data) {
+        toast(i18n.t("report_created"));
+      }
+    } else if (
+      op == UserOperation.PurgePerson ||
+      op == UserOperation.PurgePost ||
+      op == UserOperation.PurgeComment ||
+      op == UserOperation.PurgeCommunity
+    ) {
+      let data = wsJsonToRes<PurgeItemResponse>(msg, PurgeItemResponse);
+      if (data.success) {
+        toast(i18n.t("purge_success"));
+        this.context.router.history.push(`/`);
+      }
     }
   }
 }
index b3129f60cbe1c4f5c9cb87278003f641d6644db3..a93ba99ccf42a330a83dce42e90ab5166cb99e03 100644 (file)
@@ -1,34 +1,34 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component } from "inferno";
 import {
   GetPersonDetails,
   GetPersonDetailsResponse,
-  PersonViewSafe,
-  SiteView,
+  GetSiteResponse,
   SortType,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { InitialFetchRequest } from "../../interfaces";
 import { UserService, WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   getRecipientIdFromProps,
   isBrowser,
   setIsoData,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
 import { PrivateMessageForm } from "./private-message-form";
 
 interface CreatePrivateMessageState {
-  site_view: SiteView;
-  recipient: PersonViewSafe;
+  siteRes: GetSiteResponse;
+  recipientDetailsRes: Option<GetPersonDetailsResponse>;
   recipient_id: number;
   loading: boolean;
 }
@@ -37,11 +37,11 @@ export class CreatePrivateMessage extends Component<
   any,
   CreatePrivateMessageState
 > {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(this.context, GetPersonDetailsResponse);
   private subscription: Subscription;
   private emptyState: CreatePrivateMessageState = {
-    site_view: this.isoData.site_res.site_view,
-    recipient: undefined,
+    siteRes: this.isoData.site_res,
+    recipientDetailsRes: None,
     recipient_id: getRecipientIdFromProps(this.props),
     loading: true,
   };
@@ -54,14 +54,16 @@ export class CreatePrivateMessage extends Component<
     this.parseMessage = this.parseMessage.bind(this);
     this.subscription = wsSubscribe(this.parseMessage);
 
-    if (!UserService.Instance.myUserInfo) {
+    if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
       toast(i18n.t("not_logged_in"), "danger");
       this.context.router.history.push(`/login`);
     }
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      this.state.recipient = this.isoData.routeData[0].user;
+      this.state.recipientDetailsRes = Some(
+        this.isoData.routeData[0] as GetPersonDetailsResponse
+      );
       this.state.loading = false;
     } else {
       this.fetchPersonDetails();
@@ -69,30 +71,40 @@ export class CreatePrivateMessage extends Component<
   }
 
   fetchPersonDetails() {
-    let form: GetPersonDetails = {
-      person_id: this.state.recipient_id,
-      sort: SortType.New,
-      saved_only: false,
-      auth: authField(false),
-    };
+    let form = new GetPersonDetails({
+      person_id: Some(this.state.recipient_id),
+      sort: Some(SortType.New),
+      saved_only: Some(false),
+      username: None,
+      page: None,
+      limit: None,
+      community_id: None,
+      auth: auth(false).ok(),
+    });
     WebSocketService.Instance.send(wsClient.getPersonDetails(form));
   }
 
   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
-    let person_id = Number(req.path.split("/").pop());
-    let form: GetPersonDetails = {
+    let person_id = Some(Number(req.path.split("/").pop()));
+    let form = new GetPersonDetails({
       person_id,
-      sort: SortType.New,
-      saved_only: false,
+      sort: Some(SortType.New),
+      saved_only: Some(false),
+      username: None,
+      page: None,
+      limit: None,
+      community_id: None,
       auth: req.auth,
-    };
+    });
     return [req.client.getPersonDetails(form)];
   }
 
   get documentTitle(): string {
-    return `${i18n.t("create_private_message")} - ${
-      this.state.site_view.site.name
-    }`;
+    return this.state.recipientDetailsRes.match({
+      some: res =>
+        `${i18n.t("create_private_message")} - ${res.person_view.person.name}`,
+      none: "",
+    });
   }
 
   componentWillUnmount() {
@@ -107,21 +119,29 @@ export class CreatePrivateMessage extends Component<
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         {this.state.loading ? (
           <h5>
             <Spinner large />
           </h5>
         ) : (
-          <div class="row">
-            <div class="col-12 col-lg-6 offset-lg-3 mb-4">
-              <h5>{i18n.t("create_private_message")}</h5>
-              <PrivateMessageForm
-                onCreate={this.handlePrivateMessageCreate}
-                recipient={this.state.recipient.person}
-              />
-            </div>
-          </div>
+          this.state.recipientDetailsRes.match({
+            some: res => (
+              <div class="row">
+                <div class="col-12 col-lg-6 offset-lg-3 mb-4">
+                  <h5>{i18n.t("create_private_message")}</h5>
+                  <PrivateMessageForm
+                    privateMessageView={None}
+                    onCreate={this.handlePrivateMessageCreate}
+                    recipient={res.person_view.person}
+                  />
+                </div>
+              </div>
+            ),
+            none: <></>,
+          })
         )}
       </div>
     );
@@ -143,8 +163,11 @@ export class CreatePrivateMessage extends Component<
       this.setState(this.state);
       return;
     } else if (op == UserOperation.GetPersonDetails) {
-      let data = wsJsonToRes<GetPersonDetailsResponse>(msg).data;
-      this.state.recipient = data.person_view;
+      let data = wsJsonToRes<GetPersonDetailsResponse>(
+        msg,
+        GetPersonDetailsResponse
+      );
+      this.state.recipientDetailsRes = Some(data);
       this.state.loading = false;
       this.setState(this.state);
     }
index 542c48b7dbee2f0cef61b959a09689f2c5efe33f..62649816d0ea37b72efd84deadb97a2f96532582 100644 (file)
@@ -1,5 +1,6 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
-import { T } from "inferno-i18next";
+import { T } from "inferno-i18next-dess";
 import { Prompt } from "inferno-router";
 import {
   CreatePrivateMessage,
@@ -8,20 +9,21 @@ import {
   PrivateMessageResponse,
   PrivateMessageView,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
 import { i18n } from "../../i18next";
 import { WebSocketService } from "../../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
   isBrowser,
+  relTags,
   setupTippy,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../../utils";
 import { Icon, Spinner } from "../common/icon";
 import { MarkdownTextArea } from "../common/markdown-textarea";
@@ -29,7 +31,7 @@ import { PersonListing } from "../person/person-listing";
 
 interface PrivateMessageFormProps {
   recipient: PersonSafe;
-  privateMessage?: PrivateMessageView; // If a pm is given, that means this is an edit
+  privateMessageView: Option<PrivateMessageView>; // If a pm is given, that means this is an edit
   onCancel?(): any;
   onCreate?(message: PrivateMessageView): any;
   onEdit?(message: PrivateMessageView): any;
@@ -48,11 +50,11 @@ export class PrivateMessageForm extends Component<
 > {
   private subscription: Subscription;
   private emptyState: PrivateMessageFormState = {
-    privateMessageForm: {
+    privateMessageForm: new CreatePrivateMessage({
       content: null,
       recipient_id: this.props.recipient.id,
-      auth: authField(),
-    },
+      auth: auth().unwrap(),
+    }),
     loading: false,
     previewMode: false,
     showDisclaimer: false,
@@ -69,10 +71,11 @@ export class PrivateMessageForm extends Component<
     this.subscription = wsSubscribe(this.parseMessage);
 
     // Its an edit
-    if (this.props.privateMessage) {
-      this.state.privateMessageForm.content =
-        this.props.privateMessage.private_message.content;
-    }
+    this.props.privateMessageView.match({
+      some: pm =>
+        (this.state.privateMessageForm.content = pm.private_message.content),
+      none: void 0,
+    });
   }
 
   componentDidMount() {
@@ -102,7 +105,7 @@ export class PrivateMessageForm extends Component<
           message={i18n.t("block_leaving")}
         />
         <form onSubmit={linkEvent(this, this.handlePrivateMessageSubmit)}>
-          {!this.props.privateMessage && (
+          {this.props.privateMessageView.isNone() && (
             <div class="form-group row">
               <label class="col-sm-2 col-form-label">
                 {capitalizeFirstLetter(i18n.t("to"))}
@@ -127,7 +130,10 @@ export class PrivateMessageForm extends Component<
             </label>
             <div class="col-sm-10">
               <MarkdownTextArea
-                initialContent={this.state.privateMessageForm.content}
+                initialContent={Some(this.state.privateMessageForm.content)}
+                placeholder={None}
+                buttonTitle={None}
+                maxLength={None}
                 onContentChange={this.handleContentChange}
               />
             </div>
@@ -141,7 +147,7 @@ export class PrivateMessageForm extends Component<
                     #
                     <a
                       class="alert-link"
-                      rel="noopener"
+                      rel={relTags}
                       href="https://element.io/get-started"
                     >
                       #
@@ -160,13 +166,13 @@ export class PrivateMessageForm extends Component<
               >
                 {this.state.loading ? (
                   <Spinner />
-                ) : this.props.privateMessage ? (
+                ) : this.props.privateMessageView.isSome() ? (
                   capitalizeFirstLetter(i18n.t("save"))
                 ) : (
                   capitalizeFirstLetter(i18n.t("send_message"))
                 )}
               </button>
-              {this.props.privateMessage && (
+              {this.props.privateMessageView.isSome() && (
                 <button
                   type="button"
                   class="btn btn-secondary"
@@ -187,18 +193,19 @@ export class PrivateMessageForm extends Component<
 
   handlePrivateMessageSubmit(i: PrivateMessageForm, event: any) {
     event.preventDefault();
-    if (i.props.privateMessage) {
-      let form: EditPrivateMessage = {
-        private_message_id: i.props.privateMessage.private_message.id,
-        content: i.state.privateMessageForm.content,
-        auth: authField(),
-      };
-      WebSocketService.Instance.send(wsClient.editPrivateMessage(form));
-    } else {
-      WebSocketService.Instance.send(
+    i.props.privateMessageView.match({
+      some: pm => {
+        let form = new EditPrivateMessage({
+          private_message_id: pm.private_message.id,
+          content: i.state.privateMessageForm.content,
+          auth: auth().unwrap(),
+        });
+        WebSocketService.Instance.send(wsClient.editPrivateMessage(form));
+      },
+      none: WebSocketService.Instance.send(
         wsClient.createPrivateMessage(i.state.privateMessageForm)
-      );
-    }
+      ),
+    });
     i.state.loading = true;
     i.setState(i.state);
   }
@@ -236,11 +243,17 @@ export class PrivateMessageForm extends Component<
       op == UserOperation.DeletePrivateMessage ||
       op == UserOperation.MarkPrivateMessageAsRead
     ) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
       this.state.loading = false;
       this.props.onEdit(data.private_message_view);
     } else if (op == UserOperation.CreatePrivateMessage) {
-      let data = wsJsonToRes<PrivateMessageResponse>(msg).data;
+      let data = wsJsonToRes<PrivateMessageResponse>(
+        msg,
+        PrivateMessageResponse
+      );
       this.state.loading = false;
       this.props.onCreate(data.private_message_view);
       this.setState(this.state);
index 1a7c3b3376aa0552b64aaf80efd66059e398bb8b..57662606518f421cd08e384c3368b28269e28464 100644 (file)
@@ -1,3 +1,4 @@
+import { None, Some } from "@sniptt/monads/build";
 import { Component, linkEvent } from "inferno";
 import {
   DeletePrivateMessage,
@@ -7,7 +8,7 @@ import {
 } from "lemmy-js-client";
 import { i18n } from "../../i18next";
 import { UserService, WebSocketService } from "../../services";
-import { authField, mdToHtml, toast, wsClient } from "../../utils";
+import { auth, mdToHtml, toast, wsClient } from "../../utils";
 import { Icon } from "../common/icon";
 import { MomentTime } from "../common/moment-time";
 import { PersonListing } from "../person/person-listing";
@@ -46,16 +47,17 @@ export class PrivateMessage extends Component<
   }
 
   get mine(): boolean {
-    return (
-      UserService.Instance.myUserInfo &&
-      UserService.Instance.myUserInfo.local_user_view.person.id ==
-        this.props.private_message_view.creator.id
-    );
+    return UserService.Instance.myUserInfo
+      .map(
+        m =>
+          m.local_user_view.person.id ==
+          this.props.private_message_view.creator.id
+      )
+      .unwrapOr(false);
   }
 
   render() {
     let message_view = this.props.private_message_view;
-    // TODO check this again
     let otherPerson: PersonSafe = this.mine
       ? message_view.recipient
       : message_view.creator;
@@ -73,7 +75,10 @@ export class PrivateMessage extends Component<
             </li>
             <li className="list-inline-item">
               <span>
-                <MomentTime data={message_view.private_message} />
+                <MomentTime
+                  published={message_view.private_message.published}
+                  updated={message_view.private_message.updated}
+                />
               </span>
             </li>
             <li className="list-inline-item">
@@ -93,7 +98,7 @@ export class PrivateMessage extends Component<
           {this.state.showEdit && (
             <PrivateMessageForm
               recipient={otherPerson}
-              privateMessage={message_view}
+              privateMessageView={Some(message_view)}
               onEdit={this.handlePrivateMessageEdit}
               onCreate={this.handlePrivateMessageCreate}
               onCancel={this.handleReplyCancel}
@@ -207,6 +212,7 @@ export class PrivateMessage extends Component<
         {this.state.showReply && (
           <PrivateMessageForm
             recipient={otherPerson}
+            privateMessageView={None}
             onCreate={this.handlePrivateMessageCreate}
           />
         )}
@@ -232,11 +238,11 @@ export class PrivateMessage extends Component<
   }
 
   handleDeleteClick(i: PrivateMessage) {
-    let form: DeletePrivateMessage = {
+    let form = new DeletePrivateMessage({
       private_message_id: i.props.private_message_view.private_message.id,
       deleted: !i.props.private_message_view.private_message.deleted,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.deletePrivateMessage(form));
   }
 
@@ -247,11 +253,11 @@ export class PrivateMessage extends Component<
   }
 
   handleMarkRead(i: PrivateMessage) {
-    let form: MarkPrivateMessageAsRead = {
+    let form = new MarkPrivateMessageAsRead({
       private_message_id: i.props.private_message_view.private_message.id,
       read: !i.props.private_message_view.private_message.read,
-      auth: authField(),
-    };
+      auth: auth().unwrap(),
+    });
     WebSocketService.Instance.send(wsClient.markPrivateMessageAsRead(form));
   }
 
@@ -271,14 +277,15 @@ export class PrivateMessage extends Component<
   }
 
   handlePrivateMessageCreate(message: PrivateMessageView) {
-    if (
-      UserService.Instance.myUserInfo &&
-      message.creator.id ==
-        UserService.Instance.myUserInfo.local_user_view.person.id
-    ) {
-      this.state.showReply = false;
-      this.setState(this.state);
-      toast(i18n.t("message_sent"));
-    }
+    UserService.Instance.myUserInfo.match({
+      some: mui => {
+        if (message.creator.id == mui.local_user_view.person.id) {
+          this.state.showReply = false;
+          this.setState(this.state);
+          toast(i18n.t("message_sent"));
+        }
+      },
+      none: void 0,
+    });
   }
 }
index 4a1c8521559fd040b6b41626003fd3ece82d91cc..30bd9b88c2380220530e0eed0c4fa171d6a76711 100644 (file)
@@ -1,10 +1,14 @@
+import { None, Option, Some } from "@sniptt/monads";
 import { Component, linkEvent } from "inferno";
 import {
   CommentResponse,
   CommentView,
   CommunityView,
   GetCommunity,
+  GetCommunityResponse,
   GetPersonDetails,
+  GetPersonDetailsResponse,
+  GetSiteResponse,
   ListCommunities,
   ListCommunitiesResponse,
   ListingType,
@@ -16,16 +20,17 @@ import {
   Search as SearchForm,
   SearchResponse,
   SearchType,
-  Site,
   SortType,
   UserOperation,
+  wsJsonToRes,
+  wsUserOp,
 } from "lemmy-js-client";
 import { Subscription } from "rxjs";
-import { InitialFetchRequest } from "shared/interfaces";
 import { i18n } from "../i18next";
+import { CommentViewType, InitialFetchRequest } from "../interfaces";
 import { WebSocketService } from "../services";
 import {
-  authField,
+  auth,
   capitalizeFirstLetter,
   choicesConfig,
   commentsToFlatNodes,
@@ -34,25 +39,26 @@ import {
   createCommentLikeRes,
   createPostLikeFindRes,
   debounce,
+  enableDownvotes,
+  enableNsfw,
   fetchCommunities,
   fetchLimit,
   fetchUsers,
   isBrowser,
+  numToSI,
   personSelectName,
   personToChoice,
+  pushNotNull,
   restoreScrollPosition,
   routeListingTypeToEnum,
   routeSearchTypeToEnum,
   routeSortTypeToEnum,
   saveScrollPosition,
   setIsoData,
-  setOptionalAuth,
   showLocal,
   toast,
   wsClient,
-  wsJsonToRes,
   wsSubscribe,
-  wsUserOp,
 } from "../utils";
 import { CommentNodes } from "./comment/comment-nodes";
 import { HtmlTags } from "./common/html-tags";
@@ -87,13 +93,13 @@ interface SearchState {
   communityId: number;
   creatorId: number;
   page: number;
-  searchResponse: SearchResponse;
+  searchResponse: Option<SearchResponse>;
   communities: CommunityView[];
-  creator?: PersonViewSafe;
+  creatorDetails: Option<GetPersonDetailsResponse>;
   loading: boolean;
-  site: Site;
+  siteRes: GetSiteResponse;
   searchText: string;
-  resolveObjectResponse: ResolveObjectResponse;
+  resolveObjectResponse: Option<ResolveObjectResponse>;
 }
 
 interface UrlParams {
@@ -113,7 +119,14 @@ interface Combined {
 }
 
 export class Search extends Component<any, SearchState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData(
+    this.context,
+    GetCommunityResponse,
+    ListCommunitiesResponse,
+    GetPersonDetailsResponse,
+    SearchResponse,
+    ResolveObjectResponse
+  );
   private communityChoices: any;
   private creatorChoices: any;
   private subscription: Subscription;
@@ -130,21 +143,11 @@ export class Search extends Component<any, SearchState> {
       this.props.match.params.community_id
     ),
     creatorId: Search.getCreatorIdFromProps(this.props.match.params.creator_id),
-    searchResponse: {
-      type_: null,
-      posts: [],
-      comments: [],
-      communities: [],
-      users: [],
-    },
-    resolveObjectResponse: {
-      comment: null,
-      post: null,
-      community: null,
-      person: null,
-    },
+    searchResponse: None,
+    resolveObjectResponse: None,
+    creatorDetails: None,
     loading: true,
-    site: this.isoData.site_res.site_view.site,
+    siteRes: this.isoData.site_res,
     communities: [],
   };
 
@@ -189,20 +192,35 @@ export class Search extends Component<any, SearchState> {
 
     // Only fetch the data if coming from another route
     if (this.isoData.path == this.context.router.route.match.url) {
-      let singleOrMultipleCommunities = this.isoData.routeData[0];
-      if (singleOrMultipleCommunities.communities) {
-        this.state.communities = this.isoData.routeData[0].communities;
-      } else {
-        this.state.communities = [this.isoData.routeData[0].community_view];
-      }
+      let communityRes = Some(
+        this.isoData.routeData[0] as GetCommunityResponse
+      );
+      let communitiesRes = Some(
+        this.isoData.routeData[1] as ListCommunitiesResponse
+      );
+
+      // This can be single or multiple communities given
+      communitiesRes.match({
+        some: res => (this.state.communities = res.communities),
+        none: void 0,
+      });
+
+      communityRes.match({
+        some: res => (this.state.communities = [res.community_view]),
+        none: void 0,
+      });
+
+      this.state.creatorDetails = Some(
+        this.isoData.routeData[2] as GetPersonDetailsResponse
+      );
 
-      let creator = this.isoData.routeData[1];
-      if (creator?.person_view) {
-        this.state.creator = this.isoData.routeData[1].person_view;
-      }
       if (this.state.q != "") {
-        this.state.searchResponse = this.isoData.routeData[2];
-        this.state.resolveObjectResponse = this.isoData.routeData[3];
+        this.state.searchResponse = Some(
+          this.isoData.routeData[3] as SearchResponse
+        );
+        this.state.resolveObjectResponse = Some(
+          this.isoData.routeData[4] as ResolveObjectResponse
+        );
         this.state.loading = false;
       } else {
         this.search();
@@ -240,12 +258,13 @@ export class Search extends Component<any, SearchState> {
   }
 
   fetchCommunities() {
-    let listCommunitiesForm: ListCommunities = {
-      type_: ListingType.All,
-      sort: SortType.TopAll,
-      limit: fetchLimit,
-      auth: authField(false),
-    };
+    let listCommunitiesForm = new ListCommunities({
+      type_: Some(ListingType.All),
+      sort: Some(SortType.TopAll),
+      limit: Some(fetchLimit),
+      page: None,
+      auth: auth(false).ok(),
+    });
     WebSocketService.Instance.send(
       wsClient.listCommunities(listCommunitiesForm)
     );
@@ -256,57 +275,76 @@ export class Search extends Component<any, SearchState> {
     let promises: Promise<any>[] = [];
 
     let communityId = this.getCommunityIdFromProps(pathSplit[11]);
-    if (communityId !== 0) {
-      let getCommunityForm: GetCommunity = {
-        id: communityId,
-      };
-      setOptionalAuth(getCommunityForm, req.auth);
-      promises.push(req.client.getCommunity(getCommunityForm));
-    } else {
-      let listCommunitiesForm: ListCommunities = {
-        type_: ListingType.All,
-        sort: SortType.TopAll,
-        limit: fetchLimit,
-      };
-      setOptionalAuth(listCommunitiesForm, req.auth);
-      promises.push(req.client.listCommunities(listCommunitiesForm));
-    }
+    let community_id: Option<number> =
+      communityId == 0 ? None : Some(communityId);
+    community_id.match({
+      some: id => {
+        let getCommunityForm = new GetCommunity({
+          id: Some(id),
+          name: None,
+          auth: req.auth,
+        });
+        promises.push(req.client.getCommunity(getCommunityForm));
+        promises.push(Promise.resolve());
+      },
+      none: () => {
+        let listCommunitiesForm = new ListCommunities({
+          type_: Some(ListingType.All),
+          sort: Some(SortType.TopAll),
+          limit: Some(fetchLimit),
+          page: None,
+          auth: req.auth,
+        });
+        promises.push(Promise.resolve());
+        promises.push(req.client.listCommunities(listCommunitiesForm));
+      },
+    });
 
     let creatorId = this.getCreatorIdFromProps(pathSplit[13]);
-    if (creatorId !== 0) {
-      let getCreatorForm: GetPersonDetails = {
-        person_id: creatorId,
-      };
-      setOptionalAuth(getCreatorForm, req.auth);
-      promises.push(req.client.getPersonDetails(getCreatorForm));
-    } else {
-      promises.push(Promise.resolve());
-    }
+    let creator_id: Option<number> = creatorId == 0 ? None : Some(creatorId);
+    creator_id.match({
+      some: id => {
+        let getCreatorForm = new GetPersonDetails({
+          person_id: Some(id),
+          username: None,
+          sort: None,
+          page: None,
+          limit: None,
+          community_id: None,
+          saved_only: None,
+          auth: req.auth,
+        });
+        promises.push(req.client.getPersonDetails(getCreatorForm));
+      },
+      none: () => {
+        promises.push(Promise.resolve());
+      },
+    });
 
-    let form: SearchForm = {
+    let form = new SearchForm({
       q: this.getSearchQueryFromProps(pathSplit[3]),
-      type_: this.getSearchTypeFromProps(pathSplit[5]),
-      sort: this.getSortTypeFromProps(pathSplit[7]),
-      listing_type: this.getListingTypeFromProps(pathSplit[9]),
-      page: this.getPageFromProps(pathSplit[15]),
-      limit: fetchLimit,
-    };
-    if (communityId !== 0) {
-      form.community_id = communityId;
-    }
-    if (creatorId !== 0) {
-      form.creator_id = creatorId;
-    }
-    setOptionalAuth(form, req.auth);
+      community_id,
+      community_name: None,
+      creator_id,
+      type_: Some(this.getSearchTypeFromProps(pathSplit[5])),
+      sort: Some(this.getSortTypeFromProps(pathSplit[7])),
+      listing_type: Some(this.getListingTypeFromProps(pathSplit[9])),
+      page: Some(this.getPageFromProps(pathSplit[15])),
+      limit: Some(fetchLimit),
+      auth: req.auth,
+    });
 
-    let resolveObjectForm: ResolveObject = {
+    let resolveObjectForm = new ResolveObject({
       q: this.getSearchQueryFromProps(pathSplit[3]),
-    };
-    setOptionalAuth(resolveObjectForm, req.auth);
+      auth: req.auth,
+    });
 
     if (form.q != "") {
       promises.push(req.client.search(form));
       promises.push(req.client.resolveObject(resolveObjectForm));
+    } else {
+      promises.push(Promise.resolve());
+      promises.push(Promise.resolve());
     }
 
     return promises;
@@ -322,17 +360,24 @@ export class Search extends Component<any, SearchState> {
       lastState.creatorId !== this.state.creatorId ||
       lastState.page !== this.state.page
     ) {
-      this.setState({ loading: true, searchText: this.state.q });
+      this.setState({
+        loading: true,
+        searchText: this.state.q,
+        searchResponse: None,
+        resolveObjectResponse: None,
+      });
       this.search();
     }
   }
 
   get documentTitle(): string {
-    if (this.state.q) {
-      return `${i18n.t("search")} - ${this.state.q} - ${this.state.site.name}`;
-    } else {
-      return `${i18n.t("search")} - ${this.state.site.name}`;
-    }
+    return this.state.siteRes.site_view.match({
+      some: siteView =>
+        this.state.q
+          ? `${i18n.t("search")} - ${this.state.q} - ${siteView.site.name}`
+          : `${i18n.t("search")} - ${siteView.site.name}`,
+      none: "",
+    });
   }
 
   render() {
@@ -341,6 +386,8 @@ export class Search extends Component<any, SearchState> {
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
+          description={None}
+          image={None}
         />
         <h5>{i18n.t("search")}</h5>
         {this.selects()}
@@ -371,7 +418,7 @@ export class Search extends Component<any, SearchState> {
           aria-label={i18n.t("search")}
           onInput={linkEvent(this, this.handleQChange)}
           required
-          minLength={3}
+          minLength={1}
         />
         <button type="submit" class="btn btn-secondary mr-2 mb-2">
           {this.state.loading ? <Spinner /> : <span>{i18n.t("search")}</span>}
@@ -405,6 +452,7 @@ export class Search extends Component<any, SearchState> {
           <ListingTypeSelect
             type_={this.state.listingType}
             showLocal={showLocal(this.isoData)}
+            showSubscribed
             onChange={this.handleListingTypeChange}
           />
         </span>
@@ -460,42 +508,52 @@ export class Search extends Component<any, SearchState> {
     let combined: Combined[] = [];
 
     // Push the possible resolve / federated objects first
-    let resolveComment = this.state.resolveObjectResponse.comment;
-    if (resolveComment) {
-      combined.push(this.commentViewToCombined(resolveComment));
-    }
-    let resolvePost = this.state.resolveObjectResponse.post;
-    if (resolvePost) {
-      combined.push(this.postViewToCombined(resolvePost));
-    }
-    let resolveCommunity = this.state.resolveObjectResponse.community;
-    if (resolveCommunity) {
-      combined.push(this.communityViewToCombined(resolveCommunity));
-    }
-    let resolveUser = this.state.resolveObjectResponse.person;
-    if (resolveUser) {
-      combined.push(this.personViewSafeToCombined(resolveUser));
-    }
+    this.state.resolveObjectResponse.match({
+      some: res => {
+        let resolveComment = res.comment;
+        if (resolveComment.isSome()) {
+          combined.push(this.commentViewToCombined(resolveComment.unwrap()));
+        }
+        let resolvePost = res.post;
+        if (resolvePost.isSome()) {
+          combined.push(this.postViewToCombined(resolvePost.unwrap()));
+        }
+        let resolveCommunity = res.community;
+        if (resolveCommunity.isSome()) {
+          combined.push(
+            this.communityViewToCombined(resolveCommunity.unwrap())
+          );
+        }
+        let resolveUser = res.person;
+        if (resolveUser.isSome()) {
+          combined.push(this.personViewSafeToCombined(resolveUser.unwrap()));
+        }
+      },
+      none: void 0,
+    });
 
     // Push the search results
-    combined.push(
-      ...this.state.searchResponse.comments.map(e =>
-        this.commentViewToCombined(e)
-      )
-    );
-    combined.push(
-      ...this.state.searchResponse.posts.map(e => this.postViewToCombined(e))
-    );
-    combined.push(
-      ...this.state.searchResponse.communities.map(e =>
-        this.communityViewToCombined(e)
-      )
-    );
-    combined.push(
-      ...this.state.searchResponse.users.map(e =>
-        this.personViewSafeToCombined(e)
-      )
-    );
+    this.state.searchResponse.match({
+      some: res => {
+        pushNotNull(
+          combined,
+          res.comments?.map(e => this.commentViewToCombined(e))
+        );
+        pushNotNull(
+          combined,
+          res.posts?.map(e => this.postViewToCombined(e))
+        );
+        pushNotNull(
+          combined,
+          res.communities?.map(e => this.communityViewToCombined(e))
+        );
+        pushNotNull(
+          combined,
+          res.users?.map(e => this.personViewSafeToCombined(e))
+        );
+      },
+      none: void 0,
+    });
 
     // Sort it
     if (this.state.sort == SortType.New) {
@@ -525,18 +583,33 @@ export class Search extends Component<any, SearchState> {
                 <PostListing
                   key={(i.data as PostView).post.id}
                   post_view={i.data as PostView}
+                  duplicates={None}
+                  moderators={None}
+                  admins={None}
                   showCommunity
-                  enableDownvotes={this.state.site.enable_downvotes}
-                  enableNsfw={this.state.site.enable_nsfw}
+                  enableDownvotes={enableDownvotes(this.state.siteRes)}
+                  enableNsfw={enableNsfw(this.state.siteRes)}
+                  viewOnly
                 />
               )}
               {i.type_ == "comments" && (
                 <CommentNodes
                   key={(i.data as CommentView).comment.id}
-                  nodes={[{ comment_view: i.data as CommentView }]}
+                  nodes={[
+                    {
+                      comment_view: i.data as CommentView,
+                      children: [],
+                      depth: 0,
+                    },
+                  ]}
+                  viewType={CommentViewType.Flat}
+                  viewOnly
+                  moderators={None}
+                  admins={None}
+                  maxCommentsShown={None}
                   locked
                   noIndent
-                  enableDownvotes={this.state.site.enable_downvotes}
+                  enableDownvotes={enableDownvotes(this.state.siteRes)}
                 />
               )}
               {i.type_ == "communities" && (
@@ -555,19 +628,26 @@ export class Search extends Component<any, SearchState> {
   comments() {
     let comments: CommentView[] = [];
 
-    let resolveComment = this.state.resolveObjectResponse.comment;
-    if (resolveComment) {
-      comments.push(resolveComment);
-    }
-
-    comments.push(...this.state.searchResponse.comments);
+    this.state.resolveObjectResponse.match({
+      some: res => pushNotNull(comments, res.comment),
+      none: void 0,
+    });
+    this.state.searchResponse.match({
+      some: res => pushNotNull(comments, res.comments),
+      none: void 0,
+    });
 
     return (
       <CommentNodes
         nodes={commentsToFlatNodes(comments)}
+        viewType={CommentViewType.Flat}
+        viewOnly
         locked
         noIndent
-        enableDownvotes={this.state.site.enable_downvotes}
+        moderators={None}
+        admins={None}
+        maxCommentsShown={None}
+        enableDownvotes={enableDownvotes(this.state.siteRes)}
       />
     );
   }
@@ -575,12 +655,14 @@ export class Search extends Component<any, SearchState> {
   posts() {
     let posts: PostView[] = [];
 
-    let resolvePost = this.state.resolveObjectResponse.post;
-    if (resolvePost) {
-      posts.push(resolvePost);
-    }
-
-    posts.push(...this.state.searchResponse.posts);
+    this.state.resolveObjectResponse.match({
+      some: res => pushNotNull(posts, res.post),
+      none: void 0,
+    });
+    this.state.searchResponse.match({
+      some: res => pushNotNull(posts, res.posts),
+      none: void 0,
+    });
 
     return (
       <>
@@ -590,8 +672,12 @@ export class Search extends Component<any, SearchState> {
               <PostListing
                 post_view={post}
                 showCommunity
-                enableDownvotes={this.state.site.enable_downvotes}
-                enableNsfw={this.state.site.enable_nsfw}
+                duplicates={None}
+                moderators={None}
+                admins={None}
+                enableDownvotes={enableDownvotes(this.state.siteRes)}
+                enableNsfw={enableNsfw(this.state.siteRes)}
+                viewOnly
               />
             </div>
           </div>
@@ -603,12 +689,15 @@ export class Search extends Component<any, SearchState> {
   communities() {
     let communities: CommunityView[] = [];
 
-    let resolveCommunity = this.state.resolveObjectResponse.community;
-    if (resolveCommunity) {
-      communities.push(resolveCommunity);
-    }
+    this.state.resolveObjectResponse.match({
+      some: res => pushNotNull(communities, res.community),
+      none: void 0,
+    });
+    this.state.searchResponse.match({
+      some: res => pushNotNull(communities, res.communities),
+      none: void 0,
+    });
 
-    communities.push(...this.state.searchResponse.communities);
     return (
       <>
         {communities.map(community => (
@@ -623,12 +712,15 @@ export class Search extends Component<any, SearchState> {
   users() {
     let users: PersonViewSafe[] = [];
 
-    let resolveUser = this.state.resolveObjectResponse.person;
-    if (resolveUser) {
-      users.push(resolveUser);
-    }
+    this.state.resolveObjectResponse.match({
+      some: res => pushNotNull(users, res.person),
+      none: void 0,
+    });
+    this.state.searchResponse.match({
+      some: res => pushNotNull(users, res.users),
+      none: void 0,
+    });
 
-    users.push(...this.state.searchResponse.users);
     return (
       <>
         {users.map(user => (
@@ -649,6 +741,7 @@ export class Search extends Component<any, SearchState> {
         <span>{` -
         ${i18n.t("number_of_subscribers", {
           count: community_view.counts.subscribers,
+          formattedCount: numToSI(community_view.counts.subscribers),
         })}
       `}</span>
       </>
@@ -662,6 +755,7 @@ export class Search extends Component<any, SearchState> {
       </span>,
       <span>{` - ${i18n.t("number_of_comments", {
         count: person_view.counts.comment_count,
+        formattedCount: numToSI(person_view.counts.comment_count),
       })}`}</span>,
     ];
   }
@@ -701,11 +795,14 @@ export class Search extends Component<any, SearchState> {
             value={this.state.creatorId}
           >
             <option value="0">{i18n.t("all")}</option>
-            {this.state.creator && (
-              <option value={this.state.creator.person.id}>
-                {personSelectName(this.state.creator)}
-              </option>
-            )}
+            {this.state.creatorDetails.match({
+              some: creator => (
+                <option value={creator.person_view.person.id}>
+                  {personSelectName(creator.person_view)}
+                </option>
+              ),
+              none: <></>,
+            })}
           </select>
         </div>
       </div>
@@ -713,19 +810,21 @@ export class Search extends Component<any, SearchState> {
   }
 
   resultsCount(): number {
-    let res = this.state.searchResponse;
-    let resObj = this.state.resolveObjectResponse;
-    let resObjCount =
-      resObj.post || resObj.person || resObj.community || resObj.comment
-        ? 1
-        : 0;
-    return (
-      res.posts.length +
-      res.comments.length +
-      res.communities.length +
-      res.users.length +
-      resObjCount
-    );
+    let searchCount = this.state.searchResponse
+      .map(
+        r =>
+          r.posts?.length +
+          r.comments?.length +
+          r.communities?.length +
+          r.users?.length
+      )
+      .unwrapOr(0);
+
+    let resObjCount = this.state.resolveObjectResponse
+      .map(r => (r.post || r.person || r.community || r.comment ? 1 : 0))
+      .unwrapOr(0);
+
+    return resObjCount + searchCount;
   }
 
   handlePageChange(page: number) {
@@ -733,28 +832,34 @@ export class Search extends Component<any, SearchState> {
   }
 
   search() {
-    let form: SearchForm = {
+    let community_id: Option<number> =
+      this.state.communityId == 0 ? None : Some(this.state.communityId);
+    let creator_id: Option<number> =
+      this.state.creatorId == 0 ? None : Some(this.state.creatorId);
+
+    let form = new SearchForm({
       q: this.state.q,
-      type_: this.state.type_,
-      sort: this.state.sort,
-      listing_type: this.state.listingType,
-      page: this.state.page,
-      limit: fetchLimit,
-      auth: authField(false),
-    };
-    if (this.state.communityId !== 0) {
-      form.community_id = this.state.communityId;
-    }
-    if (this.state.creatorId !== 0) {
-      form.creator_id = this.state.creatorId;
-    }
+      community_id,
+      community_name: None,
+      creator_id,
+      type_: Some(this.state.type_),
+      sort: Some(this.state.sort),
+      listing_type: Some(this.state.listingType),
+      page: Some(this.state.page),
+      limit: Some(fetchLimit),
+      auth: auth(false).ok(),
+    });
 
-    let resolveObjectForm: ResolveObject = {
+    let resolveObjectForm = new ResolveObject({
       q: this.state.q,
-      auth: authField(false),
-    };
+      auth: auth(false).ok(),
+    });
 
     if (this.state.q != "") {
+      this.state.searchResponse = None;
+      this.state.resolveObjectResponse = None;
+      this.state.loading = true;
+      this.setState(this.state);
       WebSocketService.Instance.send(wsClient.search(form));
       WebSocketService.Instance.send(wsClient.resolveObject(resolveObjectForm));
     }
@@ -775,12 +880,16 @@ export class Search extends Component<any, SearchState> {
         this.communityChoices.passedElement.element.addEventListener(
           "search",
           debounce(async (e: any) => {
-            let communities = (await fetchCommunities(e.detail.value))
-              .communities;
-            let choices = communities.map(cv => communityToChoice(cv));
-            choices.unshift({ value: "0", label: i18n.t("all") });
-            this.communityChoices.setChoices(choices, "value", "label", true);
-          }, 400),
+            try {
+              let communities = (await fetchCommunities(e.detail.value))
+                .communities;
+              let choices = communities.map(cv => communityToChoice(cv));
+              choices.unshift({ value: "0", label: i18n.t("all") });
+              this.communityChoices.setChoices(choices, "value", "label", true);
+            } catch (err) {
+              console.error(err);
+            }
+          }),
           false
         );
       }
@@ -802,11 +911,15 @@ export class Search extends Component<any, SearchState> {
         this.creatorChoices.passedElement.element.addEventListener(
           "search",
           debounce(async (e: any) => {
-            let creators = (await fetchUsers(e.detail.value)).users;
-            let choices = creators.map(pvs => personToChoice(pvs));
-            choices.unshift({ value: "0", label: i18n.t("all") });
-            this.creatorChoices.setChoices(choices, "value", "label", true);
-          }, 400),
+            try {
+              let creators = (await fetchUsers(e.detail.value)).users;
+              let choices = creators.map(pvs => personToChoice(pvs));
+              choices.unshift({ value: "0", label: i18n.t("all") });
+              this.creatorChoices.setChoices(choices, "value", "label", true);
+            } catch (err) {
+              console.log(err);
+            }
+          }),
           false
         );
       }
@@ -886,45 +999,59 @@ export class Search extends Component<any, SearchState> {
     console.log(msg);
     let op = wsUserOp(msg);
     if (msg.error) {
-      if (msg.error != "couldnt_find_object") {
+      if (msg.error == "couldnt_find_object") {
+        this.state.resolveObjectResponse = Some({
+          comment: None,
+          post: None,
+          community: None,
+          person: None,
+        });
+        this.checkFinishedLoading();
+      } else {
         toast(i18n.t(msg.error), "danger");
         return;
-      } else {
-        this.setState({
-          resolveObjectResponse: {
-            comment: null,
-            community: null,
-            person: null,
-            post: null,
-          },
-        });
       }
     } else if (op == UserOperation.Search) {
-      let data = wsJsonToRes<SearchResponse>(msg).data;
-      this.state.searchResponse = data;
-      this.state.loading = false;
+      let data = wsJsonToRes<SearchResponse>(msg, SearchResponse);
+      this.state.searchResponse = Some(data);
       window.scrollTo(0, 0);
-      this.setState(this.state);
+      this.checkFinishedLoading();
       restoreScrollPosition(this.context);
     } else if (op == UserOperation.CreateCommentLike) {
-      let data = wsJsonToRes<CommentResponse>(msg).data;
+      let data = wsJsonToRes<CommentResponse>(msg, CommentResponse);
       createCommentLikeRes(
         data.comment_view,
-        this.state.searchResponse.comments
+        this.state.searchResponse.map(r => r.comments).unwrapOr([])
       );
       this.setState(this.state);
     } else if (op == UserOperation.CreatePostLike) {
-      let data = wsJsonToRes<PostResponse>(msg).data;
-      createPostLikeFindRes(data.post_view, this.state.searchResponse.posts);
+      let data = wsJsonToRes<PostResponse>(msg, PostResponse);
+      createPostLikeFindRes(
+        data.post_view,
+        this.state.searchResponse.map(r => r.posts).unwrapOr([])
+      );
       this.setState(this.state);
     } else if (op == UserOperation.ListCommunities) {
-      let data = wsJsonToRes<ListCommunitiesResponse>(msg).data;
+      let data = wsJsonToRes<ListCommunitiesResponse>(
+        msg,
+        ListCommunitiesResponse
+      );
       this.state.communities = data.communities;
       this.setState(this.state);
       this.setupCommunityFilter();
     } else if (op == UserOperation.ResolveObject) {
-      let data = wsJsonToRes<ResolveObjectResponse>(msg).data;
-      this.state.resolveObjectResponse = data;
+      let data = wsJsonToRes<ResolveObjectResponse>(msg, ResolveObjectResponse);
+      this.state.resolveObjectResponse = Some(data);
+      this.checkFinishedLoading();
+    }
+  }
+
+  checkFinishedLoading() {
+    if (
+      this.state.searchResponse.isSome() &&
+      this.state.resolveObjectResponse.isSome()
+    ) {
+      this.state.loading = false;
       this.setState(this.state);
     }
   }
index 505b5c1b0d88249b377c4743bd95b4b07c5a3241..12260e151106b9c20cc64088612a3c19f5fc9999 100644 (file)
@@ -1,9 +1,9 @@
 import { isBrowser } from "./utils";
 
-const testHost = "localhost:8536";
+const testHost = "0.0.0.0:8536";
 
 let internalHost =
-  (!isBrowser() && process.env.LEMMY_INTERNAL_HOST) || testHost; // used for local dev
+  (!isBrowser() && process.env.LEMMY_UI_LEMMY_INTERNAL_HOST) || testHost; // used for local dev
 export let externalHost: string;
 let host: string;
 let wsHost: string;
@@ -27,19 +27,22 @@ if (isBrowser()) {
   secure = window.location.protocol == "https:" ? "s" : "";
 } else {
   // server-side
-  externalHost = process.env.LEMMY_EXTERNAL_HOST || testHost;
+  externalHost = process.env.LEMMY_UI_LEMMY_EXTERNAL_HOST || testHost;
   host = internalHost;
-  wsHost = process.env.LEMMY_WS_HOST || host;
-  secure = process.env.LEMMY_HTTPS == "true" ? "s" : "";
+  wsHost = process.env.LEMMY_UI_LEMMY_WS_HOST || externalHost;
+  secure = process.env.LEMMY_UI_HTTPS == "true" ? "s" : "";
 }
 
 export const httpBaseInternal = `http://${host}`; // Don't use secure here
 export const httpBase = `http${secure}://${host}`;
-export const wsUri = `ws${secure}://${wsHost}/api/v3/ws`;
+export const wsUriBase = `ws${secure}://${wsHost}`;
+export const wsUri = `${wsUriBase}/api/v3/ws`;
 export const pictrsUri = `${httpBase}/pictrs/image`;
+export const isHttps = secure.endsWith("s");
 
 console.log(`httpbase: ${httpBase}`);
 console.log(`wsUri: ${wsUri}`);
+console.log(`isHttps: ${isHttps}`);
 
 // This is for html tags, don't include port
 const httpExternalUri = `http${secure}://${externalHost.split(":")[0]}`;
index 797d381ced399cab2593646ef11fb874f5e56e32..eaedbbf817b4fada361b862b4c7d7c33c26b3083 100644 (file)
@@ -1,8 +1,8 @@
-import i18next, { i18nTyped } from "i18next";
+import i18next, { i18nTyped, Resource } from "i18next";
 import { ar } from "./translations/ar";
 import { bg } from "./translations/bg";
 import { ca } from "./translations/ca";
-import { cy } from "./translations/cy";
+import { cs } from "./translations/cs";
 import { da } from "./translations/da";
 import { de } from "./translations/de";
 import { el } from "./translations/el";
@@ -15,81 +15,59 @@ import { fi } from "./translations/fi";
 import { fr } from "./translations/fr";
 import { ga } from "./translations/ga";
 import { gl } from "./translations/gl";
-import { hi } from "./translations/hi";
 import { hr } from "./translations/hr";
-import { hu } from "./translations/hu";
 import { id } from "./translations/id";
 import { it } from "./translations/it";
 import { ja } from "./translations/ja";
-import { ka } from "./translations/ka";
-import { km } from "./translations/km";
 import { ko } from "./translations/ko";
-import { mnc } from "./translations/mnc";
-import { nb_NO } from "./translations/nb_NO";
 import { nl } from "./translations/nl";
 import { oc } from "./translations/oc";
 import { pl } from "./translations/pl";
 import { pt } from "./translations/pt";
 import { pt_BR } from "./translations/pt_BR";
 import { ru } from "./translations/ru";
-import { sk } from "./translations/sk";
-import { sq } from "./translations/sq";
-import { sr_Latn } from "./translations/sr_Latn";
 import { sv } from "./translations/sv";
-import { th } from "./translations/th";
-import { tr } from "./translations/tr";
-import { uk } from "./translations/uk";
 import { vi } from "./translations/vi";
 import { zh } from "./translations/zh";
 import { zh_Hant } from "./translations/zh_Hant";
-import { getLanguage } from "./utils";
+import { getLanguages } from "./utils";
 
-// https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
-const resources = {
-  en,
-  el,
-  eu,
-  eo,
-  es,
-  ka,
-  hi,
-  de,
-  zh,
-  fr,
-  sv,
-  ru,
-  nl,
-  it,
-  fi,
-  ca,
-  fa,
-  pl,
-  pt_BR,
-  ja,
-  gl,
-  tr,
-  hu,
-  uk,
-  sq,
-  km,
-  ga,
-  sr_Latn,
-  da,
-  oc,
-  hr,
-  th,
-  bg,
-  ar,
-  ko,
-  id,
-  nb_NO,
-  zh_Hant,
-  cy,
-  mnc,
-  sk,
-  vi,
-  pt,
-};
+export const languages = [
+  { resource: ar, code: "ar", name: "العربية" },
+  { resource: bg, code: "bg", name: "Български" },
+  { resource: ca, code: "ca", name: "Català" },
+  { resource: cs, code: "cs", name: "Česky" },
+  { resource: da, code: "da", name: "Dansk" },
+  { resource: de, code: "de", name: "Deutsch" },
+  { resource: el, code: "el", name: "Ελληνικά" },
+  { resource: en, code: "en", name: "English" },
+  { resource: eo, code: "eo", name: "Esperanto" },
+  { resource: es, code: "es", name: "Español" },
+  { resource: eu, code: "eu", name: "Euskara" },
+  { resource: fa, code: "fa", name: "فارسی" },
+  { resource: fi, code: "fi", name: "Suomi" },
+  { resource: fr, code: "fr", name: "Français" },
+  { resource: ga, code: "ga", name: "Gaeilge" },
+  { resource: gl, code: "gl", name: "Galego" },
+  { resource: hr, code: "hr", name: "Hrvatski" },
+  { resource: id, code: "id", name: "Bahasa Indonesia" },
+  { resource: it, code: "it", name: "Italiano" },
+  { resource: ja, code: "ja", name: "日本語" },
+  { resource: ko, code: "ko", name: "한국어" },
+  { resource: nl, code: "nl", name: "Nederlands" },
+  { resource: oc, code: "oc", name: "Occitan" },
+  { resource: pl, code: "pl", name: "Polski" },
+  { resource: pt, code: "pt", name: "Português" },
+  { resource: pt_BR, code: "pt_BR", name: "Português (Brasil)" },
+  { resource: ru, code: "ru", name: "Русский" },
+  { resource: sv, code: "sv", name: "Svenska" },
+  { resource: vi, code: "vi", name: "Tiếng Việt" },
+  { resource: zh, code: "zh", name: "中文 (简体)" },
+  { resource: zh_Hant, code: "zh-TW", name: "中文 (繁體)" },
+];
+
+const resources: Resource = {};
+languages.forEach(l => (resources[l.code] = l.resource));
 
 function format(value: any, format: any): any {
   return format === "uppercase" ? value.toUpperCase() : value;
@@ -97,15 +75,13 @@ function format(value: any, format: any): any {
 
 i18next.init({
   debug: false,
+  compatibilityJSON: "v3",
   // load: 'languageOnly',
-
   // initImmediate: false,
-  lng: getLanguage(),
+  lng: getLanguages()[0],
   fallbackLng: "en",
   resources,
   interpolation: { format },
 });
 
 export const i18n = i18next as i18nTyped;
-
-export { resources };
index e09f3bd598c65ebff0208cc7ff03cbe6b41139e4..c25f5b16d155f09de702cdcb94707b2b442a3d2d 100644 (file)
@@ -1,10 +1,9 @@
-import {
-  CommentView,
-  GetSiteResponse,
-  LemmyHttp,
-  PersonMentionView,
-} from "lemmy-js-client";
+import { Either, Option } from "@sniptt/monads";
+import { GetSiteResponse, LemmyHttp } from "lemmy-js-client";
 
+/**
+ * This contains serialized data, it needs to be deserialized before use.
+ */
 export interface IsoData {
   path: string;
   routeData: any[];
@@ -23,35 +22,21 @@ declare global {
 }
 
 export interface InitialFetchRequest {
-  auth: string;
-  path: string;
+  auth: Option<string>;
   client: LemmyHttp;
-}
-
-export interface CommentNode {
-  comment_view: CommentView | PersonMentionView;
-  children?: CommentNode[];
-  depth?: number;
+  path: string;
 }
 
 export interface PostFormParams {
-  name: string;
-  url?: string;
-  body?: string;
-  community_name?: string;
-  community_id?: number;
-}
-
-export enum CommentSortType {
-  Hot,
-  Top,
-  New,
-  Old,
+  name: Option<string>;
+  url: Option<string>;
+  body: Option<string>;
+  nameOrId: Option<Either<string, number>>;
 }
 
 export enum CommentViewType {
   Tree,
-  Chat,
+  Flat,
 }
 
 export enum DataType {
@@ -70,3 +55,10 @@ export enum PersonDetailsView {
   Posts,
   Saved,
 }
+
+export enum PurgeType {
+  Person,
+  Community,
+  Post,
+  Comment,
+}
index 92c16960257fb2363f85cf8ebab0ecc13921903f..336503f220e4fc450340160e8bdc2a4d87970d84 100644 (file)
@@ -5,13 +5,18 @@ import { CreateCommunity } from "./components/community/create-community";
 import { AdminSettings } from "./components/home/admin-settings";
 import { Home } from "./components/home/home";
 import { Instances } from "./components/home/instances";
+import { Legal } from "./components/home/legal";
 import { Login } from "./components/home/login";
-import { PasswordChange } from "./components/home/password_change";
 import { Setup } from "./components/home/setup";
+import { Signup } from "./components/home/signup";
 import { Modlog } from "./components/modlog";
 import { Inbox } from "./components/person/inbox";
+import { PasswordChange } from "./components/person/password-change";
 import { Profile } from "./components/person/profile";
+import { RegistrationApplications } from "./components/person/registration-applications";
+import { Reports } from "./components/person/reports";
 import { Settings } from "./components/person/settings";
+import { VerifyEmail } from "./components/person/verify-email";
 import { CreatePost } from "./components/post/create-post";
 import { Post } from "./components/post/post";
 import { CreatePrivateMessage } from "./components/private_message/create-private-message";
@@ -38,6 +43,10 @@ export const routes: IRoutePropsWithFetch[] = [
     path: `/login`,
     component: Login,
   },
+  {
+    path: `/signup`,
+    component: Signup,
+  },
   {
     path: `/create_post`,
     component: CreatePost,
@@ -63,12 +72,12 @@ export const routes: IRoutePropsWithFetch[] = [
     fetchInitialData: req => Communities.fetchInitialData(req),
   },
   {
-    path: `/post/:id/comment/:comment_id`,
+    path: `/post/:post_id`,
     component: Post,
     fetchInitialData: req => Post.fetchInitialData(req),
   },
   {
-    path: `/post/:id`,
+    path: `/comment/:comment_id`,
     component: Post,
     fetchInitialData: req => Post.fetchInitialData(req),
   },
@@ -117,6 +126,16 @@ export const routes: IRoutePropsWithFetch[] = [
     component: AdminSettings,
     fetchInitialData: req => AdminSettings.fetchInitialData(req),
   },
+  {
+    path: `/reports`,
+    component: Reports,
+    fetchInitialData: req => Reports.fetchInitialData(req),
+  },
+  {
+    path: `/registration_applications`,
+    component: RegistrationApplications,
+    fetchInitialData: req => RegistrationApplications.fetchInitialData(req),
+  },
   {
     path: `/search/q/:q/type/:type/sort/:sort/listing_type/:listing_type/community_id/:community_id/creator_id/:creator_id/page/:page`,
     component: Search,
@@ -131,5 +150,10 @@ export const routes: IRoutePropsWithFetch[] = [
     path: `/password_change/:token`,
     component: PasswordChange,
   },
+  {
+    path: `/verify_email/:token`,
+    component: VerifyEmail,
+  },
   { path: `/instances`, component: Instances },
+  { path: `/legal`, component: Legal },
 ];
index ef6af05c2306c350316f9fcd2f4b97c38a69587f..8d591cc3ed3c0ffa2466b878683a7c374c227dbd 100644 (file)
@@ -1,8 +1,12 @@
 // import Cookies from 'js-cookie';
+import { Err, None, Ok, Option, Result, Some } from "@sniptt/monads";
 import IsomorphicCookie from "isomorphic-cookie";
 import jwt_decode from "jwt-decode";
 import { LoginResponse, MyUserInfo } from "lemmy-js-client";
-import { BehaviorSubject, Subject } from "rxjs";
+import { BehaviorSubject } from "rxjs";
+import { isHttps } from "../env";
+import { i18n } from "../i18next";
+import { isBrowser, toast } from "../utils";
 
 interface Claims {
   sub: number;
@@ -10,48 +14,70 @@ interface Claims {
   iat: number;
 }
 
+interface JwtInfo {
+  claims: Claims;
+  jwt: string;
+}
+
 export class UserService {
   private static _instance: UserService;
-  public myUserInfo: MyUserInfo;
-  public claims: Claims;
-  public jwtSub: Subject<string> = new Subject<string>();
-  public unreadCountSub: BehaviorSubject<number> = new BehaviorSubject<number>(
-    0
-  );
+  public myUserInfo: Option<MyUserInfo> = None;
+  public jwtInfo: Option<JwtInfo> = None;
+  public unreadInboxCountSub: BehaviorSubject<number> =
+    new BehaviorSubject<number>(0);
+  public unreadReportCountSub: BehaviorSubject<number> =
+    new BehaviorSubject<number>(0);
+  public unreadApplicationCountSub: BehaviorSubject<number> =
+    new BehaviorSubject<number>(0);
 
   private constructor() {
-    if (this.auth) {
-      this.setClaims(this.auth);
-    } else {
-      // setTheme();
-      console.log("No JWT cookie found.");
-    }
+    this.setJwtInfo();
   }
 
   public login(res: LoginResponse) {
     let expires = new Date();
     expires.setDate(expires.getDate() + 365);
-    IsomorphicCookie.save("jwt", res.jwt, { expires, secure: false });
-    console.log("jwt cookie set");
-    this.setClaims(res.jwt);
+    res.jwt.match({
+      some: jwt => {
+        toast(i18n.t("logged_in"));
+        IsomorphicCookie.save("jwt", jwt, { expires, secure: isHttps });
+        this.setJwtInfo();
+        location.reload();
+      },
+      none: void 0,
+    });
   }
 
   public logout() {
-    IsomorphicCookie.remove("jwt", { secure: false });
-    this.claims = undefined;
-    this.myUserInfo = undefined;
-    // setTheme();
-    this.jwtSub.next("");
-    console.log("Logged out.");
+    this.jwtInfo = None;
+    this.myUserInfo = None;
+    IsomorphicCookie.remove("jwt"); // TODO is sometimes unreliable for some reason
+    document.cookie = "jwt=; Max-Age=0; path=/; domain=" + location.host;
+    location.reload();
   }
 
-  public get auth(): string {
-    return IsomorphicCookie.load("jwt");
+  public auth(throwErr = true): Result<string, string> {
+    // Can't use match to convert to result for some reason
+    let jwt = this.jwtInfo.map(j => j.jwt);
+    if (jwt.isSome()) {
+      return Ok(jwt.unwrap());
+    } else {
+      let msg = "No JWT cookie found";
+      if (throwErr && isBrowser()) {
+        console.log(msg);
+        toast(i18n.t("not_logged_in"), "danger");
+      }
+      return Err(msg);
+    }
   }
 
-  private setClaims(jwt: string) {
-    this.claims = jwt_decode(jwt);
-    this.jwtSub.next(jwt);
+  private setJwtInfo() {
+    let jwt = IsomorphicCookie.load("jwt");
+
+    if (jwt) {
+      let jwtInfo: JwtInfo = { jwt, claims: jwt_decode(jwt) };
+      this.jwtInfo = Some(jwtInfo);
+    }
   }
 
   public static get Instance() {
index 813503960aec6dc5d445958a600af8a3d6e04e91..7d7a46d597a5d5d9c295c04c534bb454a31638f0 100644 (file)
@@ -1,45 +1,51 @@
-import { PersonViewSafe, WebSocketJsonResponse } from "lemmy-js-client";
-import {
-  default as ReconnectingWebSocket,
-  Options as WSOptions,
-} from "reconnecting-websocket";
 import { Observable } from "rxjs";
 import { share } from "rxjs/operators";
+import {
+  ExponentialBackoff,
+  LRUBuffer,
+  Websocket as WS,
+  WebsocketBuilder,
+} from "websocket-ts";
 import { wsUri } from "../env";
 import { isBrowser } from "../utils";
 
 export class WebSocketService {
   private static _instance: WebSocketService;
-  private ws: ReconnectingWebSocket;
-  public wsOptions: WSOptions = {
-    connectionTimeout: 5000,
-    maxRetries: 10,
-  };
+  private ws: WS;
   public subject: Observable<any>;
 
-  public admins: PersonViewSafe[];
-  public banned: PersonViewSafe[];
-
   private constructor() {
-    this.ws = new ReconnectingWebSocket(wsUri, [], this.wsOptions);
     let firstConnect = true;
 
     this.subject = new Observable((obs: any) => {
-      this.ws.onmessage = e => {
-        obs.next(JSON.parse(e.data));
-      };
-      this.ws.onopen = () => {
-        console.log(`Connected to ${wsUri}`);
+      this.ws = new WebsocketBuilder(wsUri)
+        .onMessage((_i, e) => {
+          try {
+            obs.next(JSON.parse(e.data.toString()));
+          } catch (err) {
+            console.error(err);
+          }
+        })
+        .onOpen(() => {
+          console.log(`Connected to ${wsUri}`);
 
-        if (!firstConnect) {
-          let res: WebSocketJsonResponse<any> = {
-            reconnect: true,
-          };
-          obs.next(res);
-        }
-
-        firstConnect = false;
-      };
+          if (!firstConnect) {
+            let res = {
+              reconnect: true,
+            };
+            obs.next(res);
+          }
+          firstConnect = false;
+        })
+        .onRetry(() => {
+          console.log("Retrying websocket connection...");
+        })
+        .onClose(() => {
+          console.error("Websocket closed.");
+        })
+        .withBackoff(new ExponentialBackoff(100, 7))
+        .withBuffer(new LRUBuffer(1000))
+        .build();
     }).pipe(share());
 
     if (isBrowser()) {
@@ -56,10 +62,6 @@ export class WebSocketService {
     this.ws.send(data);
   }
 
-  public closeEventListener(listener: (event: CloseEvent) => void) {
-    this.ws.addEventListener("close", listener);
-  }
-
   public static get Instance() {
     return this._instance || (this._instance = new this());
   }
index f9c554f8ad8013742b98a372d2778cb36b68859f..695ba1e6f392d910e258f44cead4972889928bb2 100644 (file)
@@ -1,9 +1,16 @@
+import { None, Option, Result, Some } from "@sniptt/monads";
+import { ClassConstructor, deserialize, serialize } from "class-transformer";
 import emojiShortName from "emoji-short-name";
 import {
   BlockCommunityResponse,
   BlockPersonResponse,
+  Comment as CommentI,
+  CommentNode as CommentNodeI,
+  CommentReportView,
+  CommentSortType,
   CommentView,
   CommunityBlockView,
+  CommunityModeratorView,
   CommunityView,
   GetSiteMetadata,
   GetSiteResponse,
@@ -12,70 +19,30 @@ import {
   ListingType,
   MyUserInfo,
   PersonBlockView,
+  PersonSafe,
   PersonViewSafe,
+  PostReportView,
   PostView,
   PrivateMessageView,
+  RegistrationApplicationView,
   Search,
-  SearchResponse,
   SearchType,
   SortType,
-  UserOperation,
-  WebSocketJsonResponse,
-  WebSocketResponse,
 } from "lemmy-js-client";
 import markdown_it from "markdown-it";
 import markdown_it_container from "markdown-it-container";
+import markdown_it_footnote from "markdown-it-footnote";
+import markdown_it_html5_embed from "markdown-it-html5-embed";
 import markdown_it_sub from "markdown-it-sub";
 import markdown_it_sup from "markdown-it-sup";
 import moment from "moment";
-import "moment/locale/bg";
-import "moment/locale/ca";
-import "moment/locale/cy";
-import "moment/locale/da";
-import "moment/locale/de";
-import "moment/locale/el";
-import "moment/locale/eo";
-import "moment/locale/es";
-import "moment/locale/eu";
-import "moment/locale/fa";
-import "moment/locale/fi";
-import "moment/locale/fr";
-import "moment/locale/ga";
-import "moment/locale/gl";
-import "moment/locale/hi";
-import "moment/locale/hr";
-import "moment/locale/hu";
-import "moment/locale/id";
-import "moment/locale/it";
-import "moment/locale/ja";
-import "moment/locale/ka";
-import "moment/locale/km";
-import "moment/locale/ko";
-import "moment/locale/nb";
-import "moment/locale/nl";
-import "moment/locale/pl";
-import "moment/locale/pt-br";
-import "moment/locale/ru";
-import "moment/locale/sk";
-import "moment/locale/sq";
-import "moment/locale/sr";
-import "moment/locale/sv";
-import "moment/locale/tr";
-import "moment/locale/uk";
-import "moment/locale/vi";
-import "moment/locale/zh-cn";
 import { Subscription } from "rxjs";
 import { delay, retryWhen, take } from "rxjs/operators";
 import tippy from "tippy.js";
 import Toastify from "toastify-js";
 import { httpBase } from "./env";
-import { i18n } from "./i18next";
-import {
-  CommentNode as CommentNodeI,
-  CommentSortType,
-  DataType,
-  IsoData,
-} from "./interfaces";
+import { i18n, languages } from "./i18next";
+import { DataType, IsoData } from "./interfaces";
 import { UserService, WebSocketService } from "./services";
 
 var Tribute: any;
@@ -91,78 +58,23 @@ export const favIconPngUrl = "/static/assets/icons/apple-touch-icon.png";
 // export const defaultFavIcon = `${window.location.protocol}//${window.location.host}${favIconPngUrl}`;
 export const repoUrl = "https://github.com/LemmyNet";
 export const joinLemmyUrl = "https://join-lemmy.org";
-export const supportLemmyUrl = `${joinLemmyUrl}/support`;
+export const donateLemmyUrl = `${joinLemmyUrl}/donate`;
 export const docsUrl = `${joinLemmyUrl}/docs/en/index.html`;
 export const helpGuideUrl = `${joinLemmyUrl}/docs/en/about/guide.html`; // TODO find a way to redirect to the non-en folder
-export const markdownHelpUrl = `${helpGuideUrl}#markdown-guide`;
+export const markdownHelpUrl = `${helpGuideUrl}#using-markdown`;
 export const sortingHelpUrl = `${helpGuideUrl}#sorting`;
-export const archiveUrl = "https://archive.is";
-export const elementUrl = "https://element.io/";
+export const archiveTodayUrl = "https://archive.today";
+export const ghostArchiveUrl = "https://ghostarchive.org";
+export const webArchiveUrl = "https://web.archive.org";
+export const elementUrl = "https://element.io";
 
 export const postRefetchSeconds: number = 60 * 1000;
-export const fetchLimit = 20;
+export const fetchLimit = 40;
+export const trendingFetchLimit = 6;
 export const mentionDropdownFetchLimit = 10;
+export const commentTreeMaxDepth = 8;
 
-export const languages = [
-  { code: "ca" },
-  { code: "en" },
-  { code: "el" },
-  { code: "eu" },
-  { code: "eo" },
-  { code: "es" },
-  { code: "da" },
-  { code: "de" },
-  { code: "ga" },
-  { code: "gl" },
-  { code: "hr" },
-  { code: "hu" },
-  { code: "id" },
-  { code: "ka" },
-  { code: "ko" },
-  { code: "km" },
-  { code: "hi" },
-  { code: "fa" },
-  { code: "ja" },
-  { code: "oc" },
-  { code: "nb_NO" },
-  { code: "pl" },
-  { code: "pt_BR" },
-  { code: "zh" },
-  { code: "fi" },
-  { code: "fr" },
-  { code: "sv" },
-  { code: "sq" },
-  { code: "sr_Latn" },
-  { code: "th" },
-  { code: "tr" },
-  { code: "uk" },
-  { code: "ru" },
-  { code: "nl" },
-  { code: "it" },
-  { code: "bg" },
-  { code: "zh_Hant" },
-  { code: "cy" },
-  { code: "mnc" },
-  { code: "sk" },
-  { code: "vi" },
-  { code: "pt" },
-];
-
-export const themes = [
-  "litera",
-  "materia",
-  "minty",
-  "solar",
-  "united",
-  "cyborg",
-  "darkly",
-  "journal",
-  "sketchy",
-  "vaporwave",
-  "vaporwave-dark",
-  "i386",
-  "litely",
-];
+export const relTags = "noopener nofollow";
 
 const DEFAULT_ALPHABET =
   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
@@ -186,20 +98,6 @@ export function randomStr(
     .join("");
 }
 
-export function wsJsonToRes<ResponseType>(
-  msg: WebSocketJsonResponse<ResponseType>
-): WebSocketResponse<ResponseType> {
-  return {
-    op: wsUserOp(msg),
-    data: msg.data,
-  };
-}
-
-export function wsUserOp(msg: any): UserOperation {
-  let opStr: string = msg.op;
-  return UserOperation[opStr];
-}
-
 export const md = new markdown_it({
   html: false,
   linkify: true,
@@ -207,6 +105,17 @@ export const md = new markdown_it({
 })
   .use(markdown_it_sub)
   .use(markdown_it_sup)
+  .use(markdown_it_footnote)
+  .use(markdown_it_html5_embed, {
+    html5embed: {
+      useImageSyntax: true, // Enables video/audio embed with ![]() syntax (default)
+      attributes: {
+        audio: 'controls preload="metadata"',
+        video:
+          'width="100%" max-height="100%" controls loop preload="metadata"',
+      },
+    },
+  })
   .use(markdown_it_container, "spoiler", {
     validate: function (params: any) {
       return params.trim().match(/^spoiler\s+(.*)$/);
@@ -260,37 +169,149 @@ export function getUnixTime(text: string): number {
   return text ? new Date(text).getTime() / 1000 : undefined;
 }
 
+export function futureDaysToUnixTime(days: number): number {
+  return days
+    ? Math.trunc(
+        new Date(Date.now() + 1000 * 60 * 60 * 24 * days).getTime() / 1000
+      )
+    : undefined;
+}
+
 export function canMod(
-  myUserInfo: MyUserInfo,
-  modIds: number[],
+  mods: Option<CommunityModeratorView[]>,
+  admins: Option<PersonViewSafe[]>,
   creator_id: number,
+  myUserInfo = UserService.Instance.myUserInfo,
   onSelf = false
 ): boolean {
   // You can do moderator actions only on the mods added after you.
-  if (myUserInfo) {
-    let yourIndex = modIds.findIndex(
-      id => id == myUserInfo.local_user_view.person.id
-    );
-    if (yourIndex == -1) {
-      return false;
-    } else {
-      // onSelf +1 on mod actions not for yourself, IE ban, remove, etc
-      modIds = modIds.slice(0, yourIndex + (onSelf ? 0 : 1));
-      return !modIds.includes(creator_id);
-    }
-  } else {
-    return false;
-  }
+  let adminsThenMods = admins
+    .unwrapOr([])
+    .map(a => a.person.id)
+    .concat(mods.unwrapOr([]).map(m => m.moderator.id));
+
+  return myUserInfo.match({
+    some: me => {
+      let myIndex = adminsThenMods.findIndex(
+        id => id == me.local_user_view.person.id
+      );
+      if (myIndex == -1) {
+        return false;
+      } else {
+        // onSelf +1 on mod actions not for yourself, IE ban, remove, etc
+        adminsThenMods = adminsThenMods.slice(0, myIndex + (onSelf ? 0 : 1));
+        return !adminsThenMods.includes(creator_id);
+      }
+    },
+    none: false,
+  });
 }
 
-export function isMod(modIds: number[], creator_id: number): boolean {
-  return modIds.includes(creator_id);
+export function canAdmin(
+  admins: Option<PersonViewSafe[]>,
+  creator_id: number,
+  myUserInfo = UserService.Instance.myUserInfo,
+  onSelf = false
+): boolean {
+  return canMod(None, admins, creator_id, myUserInfo, onSelf);
 }
 
-const imageRegex = new RegExp(
-  /(http)?s?:?(\/\/[^"']*\.(?:jpg|jpeg|gif|png|svg|webp))/
-);
-const videoRegex = new RegExp(`(http)?s?:?(\/\/[^"']*\.(?:mp4))`);
+export function isMod(
+  mods: Option<CommunityModeratorView[]>,
+  creator_id: number
+): boolean {
+  return mods.match({
+    some: mods => mods.map(m => m.moderator.id).includes(creator_id),
+    none: false,
+  });
+}
+
+export function amMod(
+  mods: Option<CommunityModeratorView[]>,
+  myUserInfo = UserService.Instance.myUserInfo
+): boolean {
+  return myUserInfo.match({
+    some: mui => isMod(mods, mui.local_user_view.person.id),
+    none: false,
+  });
+}
+
+export function isAdmin(
+  admins: Option<PersonViewSafe[]>,
+  creator_id: number
+): boolean {
+  return admins.match({
+    some: admins => admins.map(a => a.person.id).includes(creator_id),
+    none: false,
+  });
+}
+
+export function amAdmin(
+  admins: Option<PersonViewSafe[]>,
+  myUserInfo = UserService.Instance.myUserInfo
+): boolean {
+  return myUserInfo.match({
+    some: mui => isAdmin(admins, mui.local_user_view.person.id),
+    none: false,
+  });
+}
+
+export function amCommunityCreator(
+  mods: Option<CommunityModeratorView[]>,
+  creator_id: number,
+  myUserInfo = UserService.Instance.myUserInfo
+): boolean {
+  return mods.match({
+    some: mods =>
+      myUserInfo
+        .map(mui => mui.local_user_view.person.id)
+        .match({
+          some: myId =>
+            myId == mods[0].moderator.id &&
+            // Don't allow mod actions on yourself
+            myId != creator_id,
+          none: false,
+        }),
+    none: false,
+  });
+}
+
+export function amSiteCreator(
+  admins: Option<PersonViewSafe[]>,
+  creator_id: number,
+  myUserInfo = UserService.Instance.myUserInfo
+): boolean {
+  return admins.match({
+    some: admins =>
+      myUserInfo
+        .map(mui => mui.local_user_view.person.id)
+        .match({
+          some: myId =>
+            myId == admins[0].person.id &&
+            // Don't allow mod actions on yourself
+            myId != creator_id,
+          none: false,
+        }),
+    none: false,
+  });
+}
+
+export function amTopMod(
+  mods: Option<CommunityModeratorView[]>,
+  myUserInfo = UserService.Instance.myUserInfo
+): boolean {
+  return mods.match({
+    some: mods =>
+      myUserInfo.match({
+        some: mui => mods[0].moderator.id == mui.local_user_view.person.id,
+        none: false,
+      }),
+    none: false,
+  });
+}
+
+const imageRegex = /(http)?s?:?(\/\/[^"']*\.(?:jpg|jpeg|gif|png|svg|webp))/;
+const videoRegex = /(http)?s?:?(\/\/[^"']*\.(?:mp4|webm))/;
 
 export function isImage(url: string) {
   return imageRegex.test(url);
@@ -344,9 +365,9 @@ export function routeSearchTypeToEnum(type: string): SearchType {
 }
 
 export async function getSiteMetadata(url: string) {
-  let form: GetSiteMetadata = {
+  let form = new GetSiteMetadata({
     url,
-  };
+  });
   let client = new LemmyHttp(httpBase);
   return client.getSiteMetadata(form);
 }
@@ -392,23 +413,23 @@ export function debounce(func: any, wait = 1000, immediate = false) {
   };
 }
 
-// TODO
-export function getLanguage(override?: string): string {
-  let myUserInfo = UserService.Instance.myUserInfo;
-  let lang =
-    override ||
-    (myUserInfo?.local_user_view.local_user.lang
-      ? myUserInfo.local_user_view.local_user.lang
-      : "browser");
+export function getLanguages(
+  override?: string,
+  myUserInfo = UserService.Instance.myUserInfo
+): string[] {
+  let myLang = myUserInfo
+    .map(m => m.local_user_view.local_user.lang)
+    .unwrapOr("browser");
+  let lang = override || myLang;
 
   if (lang == "browser" && isBrowser()) {
-    return getBrowserLanguage();
+    return getBrowserLanguages();
   } else {
-    return lang;
+    return [lang];
   }
 }
 
-export function getBrowserLanguage(): string {
+function getBrowserLanguages(): string[] {
   // Intersect lemmy's langs, with the browser langs
   let langs = languages ? languages.map(l => l.code) : ["en"];
 
@@ -416,96 +437,14 @@ export function getBrowserLanguage(): string {
   let allowedLangs = navigator.languages
     .concat("en")
     .filter(v => langs.includes(v));
-  return allowedLangs[0];
-}
-
-export function getMomentLanguage(): string {
-  let lang = getLanguage();
-  if (lang.startsWith("zh")) {
-    lang = "zh-cn";
-  } else if (lang.startsWith("sv")) {
-    lang = "sv";
-  } else if (lang.startsWith("fr")) {
-    lang = "fr";
-  } else if (lang.startsWith("de")) {
-    lang = "de";
-  } else if (lang.startsWith("ru")) {
-    lang = "ru";
-  } else if (lang.startsWith("es")) {
-    lang = "es";
-  } else if (lang.startsWith("eo")) {
-    lang = "eo";
-  } else if (lang.startsWith("nl")) {
-    lang = "nl";
-  } else if (lang.startsWith("it")) {
-    lang = "it";
-  } else if (lang.startsWith("fi")) {
-    lang = "fi";
-  } else if (lang.startsWith("ca")) {
-    lang = "ca";
-  } else if (lang.startsWith("fa")) {
-    lang = "fa";
-  } else if (lang.startsWith("pl")) {
-    lang = "pl";
-  } else if (lang.startsWith("pt_BR")) {
-    lang = "pt-br";
-  } else if (lang.startsWith("ja")) {
-    lang = "ja";
-  } else if (lang.startsWith("ka")) {
-    lang = "ka";
-  } else if (lang.startsWith("hi")) {
-    lang = "hi";
-  } else if (lang.startsWith("el")) {
-    lang = "el";
-  } else if (lang.startsWith("eu")) {
-    lang = "eu";
-  } else if (lang.startsWith("gl")) {
-    lang = "gl";
-  } else if (lang.startsWith("tr")) {
-    lang = "tr";
-  } else if (lang.startsWith("hu")) {
-    lang = "hu";
-  } else if (lang.startsWith("uk")) {
-    lang = "uk";
-  } else if (lang.startsWith("sq")) {
-    lang = "sq";
-  } else if (lang.startsWith("km")) {
-    lang = "km";
-  } else if (lang.startsWith("ga")) {
-    lang = "ga";
-  } else if (lang.startsWith("sr")) {
-    lang = "sr";
-  } else if (lang.startsWith("ko")) {
-    lang = "ko";
-  } else if (lang.startsWith("da")) {
-    lang = "da";
-  } else if (lang.startsWith("oc")) {
-    lang = "oc";
-  } else if (lang.startsWith("hr")) {
-    lang = "hr";
-  } else if (lang.startsWith("th")) {
-    lang = "th";
-  } else if (lang.startsWith("bg")) {
-    lang = "bg";
-  } else if (lang.startsWith("id")) {
-    lang = "id";
-  } else if (lang.startsWith("nb")) {
-    lang = "nb";
-  } else if (lang.startsWith("cy")) {
-    lang = "cy";
-  } else if (lang.startsWith("sk")) {
-    lang = "sk";
-  } else if (lang.startsWith("vi")) {
-    lang = "vi";
-  } else if (lang.startsWith("pt")) {
-    lang = "pt";
-  } else {
-    lang = "en";
-  }
-  return lang;
+  return allowedLangs;
+}
+
+export async function fetchThemeList(): Promise<string[]> {
+  return fetch("/css/themelist").then(res => res.json());
 }
 
-export function setTheme(theme: string, forceReload = false) {
+export async function setTheme(theme: string, forceReload = false) {
   if (!isBrowser()) {
     return;
   }
@@ -517,9 +456,11 @@ export function setTheme(theme: string, forceReload = false) {
     theme = "darkly";
   }
 
+  let themeList = await fetchThemeList();
+
   // Unload all the other themes
-  for (var i = 0; i < themes.length; i++) {
-    let styleSheet = document.getElementById(themes[i]);
+  for (var i = 0; i < themeList.length; i++) {
+    let styleSheet = document.getElementById(themeList[i]);
     if (styleSheet) {
       styleSheet.setAttribute("disabled", "disabled");
     }
@@ -531,7 +472,8 @@ export function setTheme(theme: string, forceReload = false) {
   document.getElementById("default-dark")?.setAttribute("disabled", "disabled");
 
   // Load the theme dynamically
-  let cssLoc = `/static/assets/css/themes/${theme}.min.css`;
+  let cssLoc = `/css/themes/${theme}.css`;
+
   loadCss(theme, cssLoc);
   document.getElementById(theme).removeAttribute("disabled");
 }
@@ -557,24 +499,26 @@ export function objectFlip(obj: any) {
   return ret;
 }
 
-export function showAvatars(): boolean {
-  return (
-    UserService.Instance.myUserInfo?.local_user_view.local_user.show_avatars ||
-    !UserService.Instance.myUserInfo
-  );
+export function showAvatars(
+  myUserInfo: Option<MyUserInfo> = UserService.Instance.myUserInfo
+): boolean {
+  return myUserInfo
+    .map(m => m.local_user_view.local_user.show_avatars)
+    .unwrapOr(true);
 }
 
-export function showScores(): boolean {
-  return (
-    UserService.Instance.myUserInfo?.local_user_view.local_user.show_scores ||
-    !UserService.Instance.myUserInfo
-  );
+export function showScores(
+  myUserInfo: Option<MyUserInfo> = UserService.Instance.myUserInfo
+): boolean {
+  return myUserInfo
+    .map(m => m.local_user_view.local_user.show_scores)
+    .unwrapOr(true);
 }
 
 export function isCakeDay(published: string): boolean {
   // moment(undefined) or moment.utc(undefined) returns the current date/time
   // moment(null) or moment.utc(null) returns null
-  const createDate = moment.utc(published || null).local();
+  const createDate = moment.utc(published).local();
   const currentDate = moment(new Date());
 
   return (
@@ -623,7 +567,7 @@ export function pictrsDeleteToast(
 
 interface NotifyInfo {
   name: string;
-  icon?: string;
+  icon: Option<string>;
   link: string;
   body: string;
 }
@@ -635,7 +579,7 @@ export function messageToastify(info: NotifyInfo, router: any) {
 
     let toast = Toastify({
       text: `${htmlBody}<br />${info.name}`,
-      avatar: info.icon ? info.icon : null,
+      avatar: info.icon,
       backgroundColor: backgroundColor,
       className: "text-dark",
       close: true,
@@ -667,7 +611,7 @@ export function notifyComment(comment_view: CommentView, router: any) {
   let info: NotifyInfo = {
     name: comment_view.creator.name,
     icon: comment_view.creator.avatar,
-    link: `/post/${comment_view.post.id}/comment/${comment_view.comment.id}`,
+    link: `/comment/${comment_view.comment.id}`,
     body: comment_view.comment.content,
   };
   notify(info, router);
@@ -689,8 +633,8 @@ function notify(info: NotifyInfo, router: any) {
   if (Notification.permission !== "granted") Notification.requestPermission();
   else {
     var notification = new Notification(info.name, {
-      ...{body: info.body},
-      ...(info.icon && {icon: info.icon})
+      ...{ body: info.body },
+      ...(info.icon.isSome() && { icon: info.icon.unwrap() }),
     });
 
     notification.onclick = (ev: Event): any => {
@@ -732,9 +676,9 @@ export function setupTribute() {
           let it: PersonTribute = item.original;
           return `[${it.key}](${it.view.person.actor_id})`;
         },
-        values: (text: string, cb: (persons: PersonTribute[]) => any) => {
-          personSearch(text, (persons: PersonTribute[]) => cb(persons));
-        },
+        values: debounce(async (text: string, cb: any) => {
+          cb(await personSearch(text));
+        }),
         allowSpaces: false,
         autocompleteMode: true,
         // TODO
@@ -749,11 +693,9 @@ export function setupTribute() {
           let it: CommunityTribute = item.original;
           return `[${it.key}](${it.view.community.actor_id})`;
         },
-        values: (text: string, cb: any) => {
-          communitySearch(text, (communities: CommunityTribute[]) =>
-            cb(communities)
-          );
-        },
+        values: debounce(async (text: string, cb: any) => {
+          cb(await communitySearch(text));
+        }),
         allowSpaces: false,
         autocompleteMode: true,
         // TODO
@@ -785,42 +727,16 @@ interface PersonTribute {
   view: PersonViewSafe;
 }
 
-function personSearch(text: string, cb: (persons: PersonTribute[]) => any) {
-  if (text) {
-    let form: Search = {
-      q: text,
-      type_: SearchType.Users,
-      sort: SortType.TopAll,
-      listing_type: ListingType.All,
-      page: 1,
-      limit: mentionDropdownFetchLimit,
-      auth: authField(false),
+async function personSearch(text: string): Promise<PersonTribute[]> {
+  let users = (await fetchUsers(text)).users;
+  let persons: PersonTribute[] = users.map(pv => {
+    let tribute: PersonTribute = {
+      key: `@${pv.person.name}@${hostname(pv.person.actor_id)}`,
+      view: pv,
     };
-
-    WebSocketService.Instance.send(wsClient.search(form));
-
-    let personSub = WebSocketService.Instance.subject.subscribe(
-      msg => {
-        let res = wsJsonToRes(msg);
-        if (res.op == UserOperation.Search) {
-          let data = res.data as SearchResponse;
-          let persons: PersonTribute[] = data.users.map(pv => {
-            let tribute: PersonTribute = {
-              key: `@${pv.person.name}@${hostname(pv.person.actor_id)}`,
-              view: pv,
-            };
-            return tribute;
-          });
-          cb(persons);
-          personSub.unsubscribe();
-        }
-      },
-      err => console.error(err),
-      () => console.log("complete")
-    );
-  } else {
-    cb([]);
-  }
+    return tribute;
+  });
+  return persons;
 }
 
 interface CommunityTribute {
@@ -828,56 +744,32 @@ interface CommunityTribute {
   view: CommunityView;
 }
 
-function communitySearch(
-  text: string,
-  cb: (communities: CommunityTribute[]) => any
-) {
-  if (text) {
-    let form: Search = {
-      q: text,
-      type_: SearchType.Communities,
-      sort: SortType.TopAll,
-      listing_type: ListingType.All,
-      page: 1,
-      limit: mentionDropdownFetchLimit,
-      auth: authField(false),
+async function communitySearch(text: string): Promise<CommunityTribute[]> {
+  let comms = (await fetchCommunities(text)).communities;
+  let communities: CommunityTribute[] = comms.map(cv => {
+    let tribute: CommunityTribute = {
+      key: `!${cv.community.name}@${hostname(cv.community.actor_id)}`,
+      view: cv,
     };
-
-    WebSocketService.Instance.send(wsClient.search(form));
-
-    let communitySub = WebSocketService.Instance.subject.subscribe(
-      msg => {
-        let res = wsJsonToRes(msg);
-        if (res.op == UserOperation.Search) {
-          let data = res.data as SearchResponse;
-          let communities: CommunityTribute[] = data.communities.map(cv => {
-            let tribute: CommunityTribute = {
-              key: `!${cv.community.name}@${hostname(cv.community.actor_id)}`,
-              view: cv,
-            };
-            return tribute;
-          });
-          cb(communities);
-          communitySub.unsubscribe();
-        }
-      },
-      err => console.error(err),
-      () => console.log("complete")
-    );
-  } else {
-    cb([]);
-  }
+    return tribute;
+  });
+  return communities;
 }
 
-export function getListingTypeFromProps(props: any): ListingType {
+export function getListingTypeFromProps(
+  props: any,
+  defaultListingType: ListingType,
+  myUserInfo = UserService.Instance.myUserInfo
+): ListingType {
   return props.match.params.listing_type
     ? routeListingTypeToEnum(props.match.params.listing_type)
-    : UserService.Instance.myUserInfo
-    ? Object.values(ListingType)[
-        UserService.Instance.myUserInfo.local_user_view.local_user
-          .default_listing_type
-      ]
-    : ListingType.Local;
+    : myUserInfo.match({
+        some: me =>
+          Object.values(ListingType)[
+            me.local_user_view.local_user.default_listing_type
+          ],
+        none: defaultListingType,
+      });
 }
 
 export function getListingTypeFromPropsNoDefault(props: any): ListingType {
@@ -893,15 +785,19 @@ export function getDataTypeFromProps(props: any): DataType {
     : DataType.Post;
 }
 
-export function getSortTypeFromProps(props: any): SortType {
+export function getSortTypeFromProps(
+  props: any,
+  myUserInfo = UserService.Instance.myUserInfo
+): SortType {
   return props.match.params.sort
     ? routeSortTypeToEnum(props.match.params.sort)
-    : UserService.Instance.myUserInfo
-    ? Object.values(SortType)[
-        UserService.Instance.myUserInfo.local_user_view.local_user
-          .default_sort_type
-      ]
-    : SortType.Active;
+    : myUserInfo.match({
+        some: mui =>
+          Object.values(SortType)[
+            mui.local_user_view.local_user.default_sort_type
+          ],
+        none: SortType.Active,
+      });
 }
 
 export function getPageFromProps(props: any): number {
@@ -914,12 +810,14 @@ export function getRecipientIdFromProps(props: any): number {
     : 1;
 }
 
-export function getIdFromProps(props: any): number {
-  return Number(props.match.params.id);
+export function getIdFromProps(props: any): Option<number> {
+  let id: string = props.match.params.post_id;
+  return id ? Some(Number(id)) : None;
 }
 
-export function getCommentIdFromProps(props: any): number {
-  return Number(props.match.params.comment_id);
+export function getCommentIdFromProps(props: any): Option<number> {
+  let id: string = props.match.params.comment_id;
+  return id ? Some(Number(id)) : None;
 }
 
 export function getUsernameFromProps(props: any): string {
@@ -930,6 +828,7 @@ export function editCommentRes(data: CommentView, comments: CommentView[]) {
   let found = comments.find(c => c.comment.id == data.comment.id);
   if (found) {
     found.comment.content = data.comment.content;
+    found.comment.distinguished = data.comment.distinguished;
     found.comment.updated = data.comment.updated;
     found.comment.removed = data.comment.removed;
     found.comment.deleted = data.comment.deleted;
@@ -946,42 +845,53 @@ export function saveCommentRes(data: CommentView, comments: CommentView[]) {
   }
 }
 
+// TODO Should only use the return now, no state?
 export function updatePersonBlock(
-  data: BlockPersonResponse
-): PersonBlockView[] {
-  if (data.blocked) {
-    UserService.Instance.myUserInfo.person_blocks.push({
-      person: UserService.Instance.myUserInfo.local_user_view.person,
-      target: data.person_view.person,
-    });
-    toast(`${i18n.t("blocked")} ${data.person_view.person.name}`);
-  } else {
-    UserService.Instance.myUserInfo.person_blocks =
-      UserService.Instance.myUserInfo.person_blocks.filter(
-        i => i.target.id != data.person_view.person.id
-      );
-    toast(`${i18n.t("unblocked")} ${data.person_view.person.name}`);
-  }
-  return UserService.Instance.myUserInfo.person_blocks;
+  data: BlockPersonResponse,
+  myUserInfo = UserService.Instance.myUserInfo
+): Option<PersonBlockView[]> {
+  return myUserInfo.match({
+    some: (mui: MyUserInfo) => {
+      if (data.blocked) {
+        mui.person_blocks.push({
+          person: mui.local_user_view.person,
+          target: data.person_view.person,
+        });
+        toast(`${i18n.t("blocked")} ${data.person_view.person.name}`);
+      } else {
+        mui.person_blocks = mui.person_blocks.filter(
+          i => i.target.id != data.person_view.person.id
+        );
+        toast(`${i18n.t("unblocked")} ${data.person_view.person.name}`);
+      }
+      return Some(mui.person_blocks);
+    },
+    none: None,
+  });
 }
 
 export function updateCommunityBlock(
-  data: BlockCommunityResponse
-): CommunityBlockView[] {
-  if (data.blocked) {
-    UserService.Instance.myUserInfo.community_blocks.push({
-      person: UserService.Instance.myUserInfo.local_user_view.person,
-      community: data.community_view.community,
-    });
-    toast(`${i18n.t("blocked")} ${data.community_view.community.name}`);
-  } else {
-    UserService.Instance.myUserInfo.community_blocks =
-      UserService.Instance.myUserInfo.community_blocks.filter(
-        i => i.community.id != data.community_view.community.id
-      );
-    toast(`${i18n.t("unblocked")} ${data.community_view.community.name}`);
-  }
-  return UserService.Instance.myUserInfo.community_blocks;
+  data: BlockCommunityResponse,
+  myUserInfo = UserService.Instance.myUserInfo
+): Option<CommunityBlockView[]> {
+  return myUserInfo.match({
+    some: (mui: MyUserInfo) => {
+      if (data.blocked) {
+        mui.community_blocks.push({
+          person: mui.local_user_view.person,
+          community: data.community_view.community,
+        });
+        toast(`${i18n.t("blocked")} ${data.community_view.community.name}`);
+      } else {
+        mui.community_blocks = mui.community_blocks.filter(
+          i => i.community.id != data.community_view.community.id
+        );
+        toast(`${i18n.t("unblocked")} ${data.community_view.community.name}`);
+      }
+      return Some(mui.community_blocks);
+    },
+    none: None,
+  });
 }
 
 export function createCommentLikeRes(
@@ -1038,63 +948,49 @@ export function editPostRes(data: PostView, post: PostView) {
   }
 }
 
-export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
-  let nodes: CommentNodeI[] = [];
-  for (let comment of comments) {
-    nodes.push({ comment_view: comment });
+export function updatePostReportRes(
+  data: PostReportView,
+  reports: PostReportView[]
+) {
+  let found = reports.find(p => p.post_report.id == data.post_report.id);
+  if (found) {
+    found.post_report = data.post_report;
   }
-  return nodes;
 }
 
-function commentSort(tree: CommentNodeI[], sort: CommentSortType) {
-  // First, put removed and deleted comments at the bottom, then do your other sorts
-  if (sort == CommentSortType.Top) {
-    tree.sort(
-      (a, b) =>
-        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
-        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
-        b.comment_view.counts.score - a.comment_view.counts.score
-    );
-  } else if (sort == CommentSortType.New) {
-    tree.sort(
-      (a, b) =>
-        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
-        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
-        b.comment_view.comment.published.localeCompare(
-          a.comment_view.comment.published
-        )
-    );
-  } else if (sort == CommentSortType.Old) {
-    tree.sort(
-      (a, b) =>
-        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
-        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
-        a.comment_view.comment.published.localeCompare(
-          b.comment_view.comment.published
-        )
-    );
-  } else if (sort == CommentSortType.Hot) {
-    tree.sort(
-      (a, b) =>
-        +a.comment_view.comment.removed - +b.comment_view.comment.removed ||
-        +a.comment_view.comment.deleted - +b.comment_view.comment.deleted ||
-        hotRankComment(b.comment_view) - hotRankComment(a.comment_view)
-    );
+export function updateCommentReportRes(
+  data: CommentReportView,
+  reports: CommentReportView[]
+) {
+  let found = reports.find(c => c.comment_report.id == data.comment_report.id);
+  if (found) {
+    found.comment_report = data.comment_report;
   }
+}
 
-  // Go through the children recursively
-  for (let node of tree) {
-    if (node.children) {
-      commentSort(node.children, sort);
-    }
+export function updateRegistrationApplicationRes(
+  data: RegistrationApplicationView,
+  applications: RegistrationApplicationView[]
+) {
+  let found = applications.find(
+    ra => ra.registration_application.id == data.registration_application.id
+  );
+  if (found) {
+    found.registration_application = data.registration_application;
+    found.admin = data.admin;
+    found.creator_local_user = data.creator_local_user;
   }
 }
 
-export function commentSortSortType(tree: CommentNodeI[], sort: SortType) {
-  commentSort(tree, convertCommentSortType(sort));
+export function commentsToFlatNodes(comments: CommentView[]): CommentNodeI[] {
+  let nodes: CommentNodeI[] = [];
+  for (let comment of comments) {
+    nodes.push({ comment_view: comment, children: [], depth: 0 });
+  }
+  return nodes;
 }
 
-function convertCommentSortType(sort: SortType): CommentSortType {
+export function convertCommentSortType(sort: SortType): CommentSortType {
   if (
     sort == SortType.TopAll ||
     sort == SortType.TopDay ||
@@ -1114,46 +1010,72 @@ function convertCommentSortType(sort: SortType): CommentSortType {
 
 export function buildCommentsTree(
   comments: CommentView[],
-  commentSortType: CommentSortType
+  parentComment: boolean
 ): CommentNodeI[] {
   let map = new Map<number, CommentNodeI>();
+  let depthOffset = !parentComment
+    ? 0
+    : getDepthFromComment(comments[0].comment);
+
   for (let comment_view of comments) {
     let node: CommentNodeI = {
       comment_view: comment_view,
       children: [],
+      depth: getDepthFromComment(comment_view.comment) - depthOffset,
     };
     map.set(comment_view.comment.id, { ...node });
   }
+
   let tree: CommentNodeI[] = [];
-  for (let comment_view of comments) {
-    let child = map.get(comment_view.comment.id);
-    let parent_id = comment_view.comment.parent_id;
-    if (parent_id) {
-      let parent = map.get(parent_id);
-      // Necessary because blocked comment might not exist
-      if (parent) {
-        parent.children.push(child);
-      }
-    } else {
-      tree.push(child);
-    }
 
-    setDepth(child);
+  // if its a parent comment fetch, then push the first comment to the top node.
+  if (parentComment) {
+    tree.push(map.get(comments[0].comment.id));
   }
 
-  commentSort(tree, commentSortType);
+  for (let comment_view of comments) {
+    let child = map.get(comment_view.comment.id);
+    let parent_id = getCommentParentId(comment_view.comment);
+    parent_id.match({
+      some: parentId => {
+        let parent = map.get(parentId);
+        // Necessary because blocked comment might not exist
+        if (parent) {
+          parent.children.push(child);
+        }
+      },
+      none: () => {
+        if (!parentComment) {
+          tree.push(child);
+        }
+      },
+    });
+  }
 
   return tree;
 }
 
-function setDepth(node: CommentNodeI, i = 0) {
-  for (let child of node.children) {
-    child.depth = i;
-    setDepth(child, i + 1);
+export function getCommentParentId(comment: CommentI): Option<number> {
+  let split = comment.path.split(".");
+  // remove the 0
+  split.shift();
+
+  if (split.length > 1) {
+    return Some(Number(split[split.length - 2]));
+  } else {
+    return None;
   }
 }
 
-export function insertCommentIntoTree(tree: CommentNodeI[], cv: CommentView) {
+export function getDepthFromComment(comment: CommentI): number {
+  return comment.path.split(".").length - 2;
+}
+
+export function insertCommentIntoTree(
+  tree: CommentNodeI[],
+  cv: CommentView,
+  parentComment: boolean
+) {
   // Building a fake node to be used for later
   let node: CommentNodeI = {
     comment_view: cv,
@@ -1161,39 +1083,48 @@ export function insertCommentIntoTree(tree: CommentNodeI[], cv: CommentView) {
     depth: 0,
   };
 
-  if (cv.comment.parent_id) {
-    let parentComment = searchCommentTree(tree, cv.comment.parent_id);
-    if (parentComment) {
-      node.depth = parentComment.depth + 1;
-      parentComment.children.unshift(node);
-    }
-  } else {
-    tree.unshift(node);
-  }
+  getCommentParentId(cv.comment).match({
+    some: parentId => {
+      let parentComment = searchCommentTree(tree, parentId);
+      parentComment.match({
+        some: pComment => {
+          node.depth = pComment.depth + 1;
+          pComment.children.unshift(node);
+        },
+        none: void 0,
+      });
+    },
+    none: () => {
+      if (!parentComment) {
+        tree.unshift(node);
+      }
+    },
+  });
 }
 
 export function searchCommentTree(
   tree: CommentNodeI[],
   id: number
-): CommentNodeI {
+): Option<CommentNodeI> {
   for (let node of tree) {
     if (node.comment_view.comment.id === id) {
-      return node;
+      return Some(node);
     }
 
     for (const child of node.children) {
-      const res = searchCommentTree([child], id);
+      let res = searchCommentTree([child], id);
 
-      if (res) {
+      if (res.isSome()) {
         return res;
       }
     }
   }
-  return null;
+  return None;
 }
 
 export const colorList: string[] = [
   hsl(0),
+  hsl(50),
   hsl(100),
   hsl(150),
   hsl(200),
@@ -1205,21 +1136,6 @@ function hsl(num: number) {
   return `hsla(${num}, 35%, 50%, 1)`;
 }
 
-export function previewLines(
-  text: string,
-  maxChars = 300,
-  maxLines = 1
-): string {
-  return (
-    text
-      .slice(0, maxChars)
-      .split("\n")
-      // Use lines * 2 because markdown requires 2 lines
-      .slice(0, maxLines * 2)
-      .join("\n") + "..."
-  );
-}
-
 export function hostname(url: string): string {
   let cUrl = new URL(url);
   return cUrl.port ? `${cUrl.hostname}:${cUrl.port}` : `${cUrl.hostname}`;
@@ -1227,7 +1143,7 @@ export function hostname(url: string): string {
 
 export function validTitle(title?: string): boolean {
   // Initial title is null, minimum length is taken care of by textarea's minLength={3}
-  if (title === null || title.length < 3) return true;
+  if (!title || title.length < 3) return true;
 
   const regex = new RegExp(/.*\S.*/, "g");
 
@@ -1251,11 +1167,52 @@ export function isBrowser() {
   return typeof window !== "undefined";
 }
 
-export function setIsoData(context: any): IsoData {
-  let isoData: IsoData = isBrowser()
-    ? window.isoData
-    : context.router.staticContext;
-  return isoData;
+export function setIsoData<Type1, Type2, Type3, Type4, Type5>(
+  context: any,
+  cls1?: ClassConstructor<Type1>,
+  cls2?: ClassConstructor<Type2>,
+  cls3?: ClassConstructor<Type3>,
+  cls4?: ClassConstructor<Type4>,
+  cls5?: ClassConstructor<Type5>
+): IsoData {
+  // If its the browser, you need to deserialize the data from the window
+  if (isBrowser()) {
+    let json = window.isoData;
+    let routeData = json.routeData;
+    let routeDataOut: any[] = [];
+
+    // Can't do array looping because of specific type constructor required
+    if (routeData[0]) {
+      routeDataOut[0] = convertWindowJson(cls1, routeData[0]);
+    }
+    if (routeData[1]) {
+      routeDataOut[1] = convertWindowJson(cls2, routeData[1]);
+    }
+    if (routeData[2]) {
+      routeDataOut[2] = convertWindowJson(cls3, routeData[2]);
+    }
+    if (routeData[3]) {
+      routeDataOut[3] = convertWindowJson(cls4, routeData[3]);
+    }
+    if (routeData[4]) {
+      routeDataOut[4] = convertWindowJson(cls5, routeData[4]);
+    }
+    let site_res = convertWindowJson(GetSiteResponse, json.site_res);
+
+    let isoData: IsoData = {
+      path: json.path,
+      site_res,
+      routeData: routeDataOut,
+    };
+    return isoData;
+  } else return context.router.staticContext;
+}
+
+/**
+ * Necessary since window ISOData can't store function types like Option
+ */
+export function convertWindowJson<T>(cls: ClassConstructor<T>, data: any): T {
+  return deserialize(cls, serialize(data));
 }
 
 export function wsSubscribe(parseMessage: any): Subscription {
@@ -1272,24 +1229,6 @@ export function wsSubscribe(parseMessage: any): Subscription {
   }
 }
 
-export function setOptionalAuth(obj: any, auth = UserService.Instance.auth) {
-  if (auth) {
-    obj.auth = auth;
-  }
-}
-
-export function authField(
-  throwErr = true,
-  auth = UserService.Instance.auth
-): string {
-  if (auth == null && throwErr) {
-    toast(i18n.t("not_logged_in"), "danger");
-    throw "Not logged in";
-  } else {
-    return auth;
-  }
-}
-
 moment.updateLocale("en", {
   relativeTime: {
     future: "in %s",
@@ -1324,10 +1263,12 @@ export function restoreScrollPosition(context: any) {
 }
 
 export function showLocal(isoData: IsoData): boolean {
-  return isoData.site_res.federated_instances?.linked.length > 0;
+  return isoData.site_res.federated_instances
+    .map(f => f.linked.length > 0)
+    .unwrapOr(false);
 }
 
-interface ChoicesValue {
+export interface ChoicesValue {
   value: string;
   label: string;
 }
@@ -1349,29 +1290,35 @@ export function personToChoice(pvs: PersonViewSafe): ChoicesValue {
 }
 
 export async function fetchCommunities(q: string) {
-  let form: Search = {
+  let form = new Search({
     q,
-    type_: SearchType.Communities,
-    sort: SortType.TopAll,
-    listing_type: ListingType.All,
-    page: 1,
-    limit: fetchLimit,
-    auth: authField(false),
-  };
+    type_: Some(SearchType.Communities),
+    sort: Some(SortType.TopAll),
+    listing_type: Some(ListingType.All),
+    page: Some(1),
+    limit: Some(fetchLimit),
+    community_id: None,
+    community_name: None,
+    creator_id: None,
+    auth: auth(false).ok(),
+  });
   let client = new LemmyHttp(httpBase);
   return client.search(form);
 }
 
 export async function fetchUsers(q: string) {
-  let form: Search = {
+  let form = new Search({
     q,
-    type_: SearchType.Users,
-    sort: SortType.TopAll,
-    listing_type: ListingType.All,
-    page: 1,
-    limit: fetchLimit,
-    auth: authField(false),
-  };
+    type_: Some(SearchType.Users),
+    sort: Some(SortType.TopAll),
+    listing_type: Some(ListingType.All),
+    page: Some(1),
+    limit: Some(fetchLimit),
+    community_id: None,
+    community_name: None,
+    creator_id: None,
+    auth: auth(false).ok(),
+  });
   let client = new LemmyHttp(httpBase);
   return client.search(form);
 }
@@ -1409,19 +1356,108 @@ export const choicesConfig = {
   },
 };
 
+export const choicesModLogConfig = {
+  shouldSort: false,
+  searchResultLimit: fetchLimit,
+  classNames: {
+    containerOuter: "choices mb-2 custom-select col-4 px-0",
+    containerInner:
+      "choices__inner bg-secondary border-0 py-0 modlog-choices-font-size",
+    input: "form-control",
+    inputCloned: "choices__input--cloned w-100",
+    list: "choices__list",
+    listItems: "choices__list--multiple",
+    listSingle: "choices__list--single py-0",
+    listDropdown: "choices__list--dropdown",
+    item: "choices__item bg-secondary",
+    itemSelectable: "choices__item--selectable",
+    itemDisabled: "choices__item--disabled",
+    itemChoice: "choices__item--choice",
+    placeholder: "choices__placeholder",
+    group: "choices__group",
+    groupHeading: "choices__heading",
+    button: "choices__button",
+    activeState: "is-active",
+    focusState: "is-focused",
+    openState: "is-open",
+    disabledState: "is-disabled",
+    highlightedState: "text-info",
+    selectedState: "text-info",
+    flippedState: "is-flipped",
+    loadingState: "is-loading",
+    noResults: "has-no-results",
+    noChoices: "has-no-choices",
+  },
+};
+
 export function communitySelectName(cv: CommunityView): string {
   return cv.community.local
-    ? cv.community.name
-    : `${hostname(cv.community.actor_id)}/${cv.community.name}`;
+    ? cv.community.title
+    : `${hostname(cv.community.actor_id)}/${cv.community.title}`;
 }
 
 export function personSelectName(pvs: PersonViewSafe): string {
-  return pvs.person.local
-    ? pvs.person.name
-    : `${hostname(pvs.person.actor_id)}/${pvs.person.name}`;
+  let pName = pvs.person.display_name.unwrapOr(pvs.person.name);
+  return pvs.person.local ? pName : `${hostname(pvs.person.actor_id)}/${pName}`;
 }
 
 export function initializeSite(site: GetSiteResponse) {
   UserService.Instance.myUserInfo = site.my_user;
-  i18n.changeLanguage(getLanguage());
+  i18n.changeLanguage(getLanguages()[0]);
+}
+
+const SHORTNUM_SI_FORMAT = new Intl.NumberFormat("en-US", {
+  maximumSignificantDigits: 3,
+  //@ts-ignore
+  notation: "compact",
+  compactDisplay: "short",
+});
+
+export function numToSI(value: number): string {
+  return SHORTNUM_SI_FORMAT.format(value);
+}
+
+export function isBanned(ps: PersonSafe): boolean {
+  let expires = ps.ban_expires;
+  // Add Z to convert from UTC date
+  // TODO this check probably isn't necessary anymore
+  if (expires.isSome()) {
+    if (ps.banned && new Date(expires.unwrap() + "Z") > new Date()) {
+      return true;
+    } else {
+      return false;
+    }
+  } else {
+    return ps.banned;
+  }
+}
+
+export function pushNotNull(array: any[], new_item?: any) {
+  if (new_item) {
+    array.push(...new_item);
+  }
+}
+
+export function auth(throwErr = true): Result<string, string> {
+  return UserService.Instance.auth(throwErr);
+}
+
+export function enableDownvotes(siteRes: GetSiteResponse): boolean {
+  return siteRes.site_view.map(s => s.site.enable_downvotes).unwrapOr(true);
+}
+
+export function enableNsfw(siteRes: GetSiteResponse): boolean {
+  return siteRes.site_view.map(s => s.site.enable_nsfw).unwrapOr(false);
+}
+
+export function postToCommentSortType(sort: SortType): CommentSortType {
+  if ([SortType.Active, SortType.Hot].includes(sort)) {
+    return CommentSortType.Hot;
+  } else if ([SortType.New, SortType.NewComments].includes(sort)) {
+    return CommentSortType.New;
+  } else if (sort == SortType.Old) {
+    return CommentSortType.Old;
+  } else {
+    return CommentSortType.Top;
+  }
 }
index cd9bc8d0b35161873a380449592f00244a6bedbc..c708247264f5d763eda62ce550c7198c1e0d0bec 100644 (file)
@@ -18,7 +18,8 @@
                "skipLibCheck": true,\r
                "noUnusedParameters": true,\r
                "noImplicitReturns": true,\r
-               "noFallthroughCasesInSwitch": true\r
+    "experimentalDecorators": true,\r
+    "noFallthroughCasesInSwitch": true\r
        },\r
        "include": [\r
                "src/**/*",\r
index 8ea0fbd559e7c559a8521f7fde73b28c307f99fa..315c90018cca6f835255132ce8d8fbdfa4f43e15 100644 (file)
@@ -1,9 +1,9 @@
-const webpack = require('webpack');
-const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const nodeExternals = require('webpack-node-externals');
-const CopyPlugin = require('copy-webpack-plugin');
-const RunNodeWebpackPlugin = require('run-node-webpack-plugin');
-const { merge } = require('lodash');
+const webpack = require("webpack");
+const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const nodeExternals = require("webpack-node-externals");
+const CopyPlugin = require("copy-webpack-plugin");
+const RunNodeWebpackPlugin = require("run-node-webpack-plugin");
+const { merge } = require("lodash");
 
 const banner = `
   hash:[contentHash], chunkhash:[chunkhash], name:[name], filebase:[base], query:[query], file:[file]
@@ -14,11 +14,12 @@ const banner = `
 
 const base = {
   output: {
-    filename: 'js/server.js',
-    publicPath: '/',
+    filename: "js/server.js",
+    publicPath: "/",
+    hashFunction: "xxhash64",
   },
   resolve: {
-    extensions: ['.js', '.jsx', '.ts', '.tsx'],
+    extensions: [".js", ".jsx", ".ts", ".tsx"],
   },
   performance: {
     hints: false,
@@ -27,12 +28,12 @@ const base = {
     rules: [
       {
         test: /\.(scss|css)$/i,
-        use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
+        use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
       },
       {
         test: /\.(js|jsx|tsx|ts)$/, // All ts and tsx files will be process by
         exclude: /node_modules/, // ignore node_modules
-        loader: 'babel-loader',
+        loader: "babel-loader",
       },
       // Due to some weird babel issue: https://github.com/webpack/webpack/issues/11467
       {
@@ -45,10 +46,10 @@ const base = {
   },
   plugins: [
     new MiniCssExtractPlugin({
-      filename: 'styles/styles.css',
+      filename: "styles/styles.css",
     }),
     new CopyPlugin({
-      patterns: [{ from: './src/assets', to: './assets' }],
+      patterns: [{ from: "./src/assets", to: "./assets" }],
     }),
     new webpack.BannerPlugin({
       banner,
@@ -59,18 +60,18 @@ const base = {
 const createServerConfig = (_env, mode) => {
   const config = merge({}, base, {
     mode,
-    entry: './src/server/index.tsx',
+    entry: "./src/server/index.tsx",
     output: {
-      filename: 'js/server.js',
+      filename: "js/server.js",
     },
-    target: 'node',
-    externals: [nodeExternals(), 'inferno-helmet'],
+    target: "node",
+    externals: [nodeExternals(), "inferno-helmet"],
   });
 
-  if (mode === 'development') {
+  if (mode === "development") {
     config.cache = {
-      type: 'filesystem',
-      name: 'server',
+      type: "filesystem",
+      name: "server",
     };
 
     config.plugins.push(
@@ -85,16 +86,16 @@ const createServerConfig = (_env, mode) => {
 const createClientConfig = (_env, mode) => {
   const config = merge({}, base, {
     mode,
-    entry: './src/client/index.tsx',
+    entry: "./src/client/index.tsx",
     output: {
-      filename: 'js/client.js',
+      filename: "js/client.js",
     },
   });
 
-  if (mode === 'development') {
+  if (mode === "development") {
     config.cache = {
-      type: 'filesystem',
-      name: 'client',
+      type: "filesystem",
+      name: "client",
     };
   }
 
@@ -102,6 +103,6 @@ const createClientConfig = (_env, mode) => {
 };
 
 module.exports = (env, properties) => [
-  createServerConfig(env, properties.mode || 'development'),
-  createClientConfig(env, properties.mode || 'development'),
+  createServerConfig(env, properties.mode || "development"),
+  createClientConfig(env, properties.mode || "development"),
 ];
index bf33823dbe48097618ee8f095bad50941279079c..93f1f5d0f233e6a7b8ce15bdffd9dfdc74cc4c59 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -2,39 +2,77 @@
 # yarn lockfile v1
 
 
-"@babel/code-frame@7.12.11":
-  version "7.12.11"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
-  integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
-  dependencies:
-    "@babel/highlight" "^7.10.4"
+"@ampproject/remapping@^2.1.0":
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34"
+  integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==
+  dependencies:
+    "@jridgewell/trace-mapping" "^0.3.0"
+
+"@babel/code-frame@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
+  integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==
+  dependencies:
+    "@babel/highlight" "^7.16.7"
+
+"@babel/code-frame@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
+  integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
+  dependencies:
+    "@babel/highlight" "^7.18.6"
+
+"@babel/compat-data@^7.16.4":
+  version "7.16.8"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60"
+  integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==
+
+"@babel/compat-data@^7.17.7":
+  version "7.17.7"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2"
+  integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ==
+
+"@babel/compat-data@^7.18.8":
+  version "7.18.8"
+  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
+  integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
+
+"@babel/core@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59"
+  integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
+  dependencies:
+    "@ampproject/remapping" "^2.1.0"
+    "@babel/code-frame" "^7.18.6"
+    "@babel/generator" "^7.18.9"
+    "@babel/helper-compilation-targets" "^7.18.9"
+    "@babel/helper-module-transforms" "^7.18.9"
+    "@babel/helpers" "^7.18.9"
+    "@babel/parser" "^7.18.9"
+    "@babel/template" "^7.18.6"
+    "@babel/traverse" "^7.18.9"
+    "@babel/types" "^7.18.9"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.2"
+    json5 "^2.2.1"
+    semver "^6.3.0"
 
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb"
-  integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==
-  dependencies:
-    "@babel/highlight" "^7.14.5"
-
-"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176"
-  integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==
-
-"@babel/core@^7.14.6", "@babel/core@^7.2.2":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.0.tgz#749e57c68778b73ad8082775561f67f5196aafa8"
-  integrity sha512-tXtmTminrze5HEUPn/a0JtOzzfp0nk+UEXQ/tqIJo3WDGypl/2OFQEMll/zSFU8f/lfmfLXvTaORHF3cfXIQMw==
-  dependencies:
-    "@babel/code-frame" "^7.14.5"
-    "@babel/generator" "^7.15.0"
-    "@babel/helper-compilation-targets" "^7.15.0"
-    "@babel/helper-module-transforms" "^7.15.0"
-    "@babel/helpers" "^7.14.8"
-    "@babel/parser" "^7.15.0"
-    "@babel/template" "^7.14.5"
-    "@babel/traverse" "^7.15.0"
-    "@babel/types" "^7.15.0"
+"@babel/core@^7.2.2":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf"
+  integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==
+  dependencies:
+    "@babel/code-frame" "^7.16.7"
+    "@babel/generator" "^7.16.7"
+    "@babel/helper-compilation-targets" "^7.16.7"
+    "@babel/helper-module-transforms" "^7.16.7"
+    "@babel/helpers" "^7.16.7"
+    "@babel/parser" "^7.16.7"
+    "@babel/template" "^7.16.7"
+    "@babel/traverse" "^7.16.7"
+    "@babel/types" "^7.16.7"
     convert-source-map "^1.7.0"
     debug "^4.1.0"
     gensync "^1.0.0-beta.2"
     semver "^6.3.0"
     source-map "^0.5.0"
 
-"@babel/generator@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.15.0.tgz#a7d0c172e0d814974bad5aa77ace543b97917f15"
-  integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==
+"@babel/generator@^7.16.7", "@babel/generator@^7.16.8":
+  version "7.16.8"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe"
+  integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==
   dependencies:
-    "@babel/types" "^7.15.0"
+    "@babel/types" "^7.16.8"
     jsesc "^2.5.1"
     source-map "^0.5.0"
 
-"@babel/helper-annotate-as-pure@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.14.5.tgz#7bf478ec3b71726d56a8ca5775b046fc29879e61"
-  integrity sha512-EivH9EgBIb+G8ij1B2jAwSH36WnGvkQSEC6CkX/6v6ZFlw5fVOHvsgGF4uiEHO2GzMvunZb6tDLQEQSdrdocrA==
-  dependencies:
-    "@babel/types" "^7.14.5"
-
-"@babel/helper-builder-binary-assignment-operator-visitor@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.14.5.tgz#b939b43f8c37765443a19ae74ad8b15978e0a191"
-  integrity sha512-YTA/Twn0vBXDVGJuAX6PwW7x5zQei1luDDo2Pl6q1qZ7hVNl0RZrhHCQG/ArGpR29Vl7ETiB8eJyrvpuRp300w==
-  dependencies:
-    "@babel/helper-explode-assignable-expression" "^7.14.5"
-    "@babel/types" "^7.14.5"
-
-"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz#973df8cbd025515f3ff25db0c05efc704fa79818"
-  integrity sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==
-  dependencies:
-    "@babel/compat-data" "^7.15.0"
-    "@babel/helper-validator-option" "^7.14.5"
-    browserslist "^4.16.6"
-    semver "^6.3.0"
-
-"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.0.tgz#c9a137a4d137b2d0e2c649acf536d7ba1a76c0f7"
-  integrity sha512-MdmDXgvTIi4heDVX/e9EFfeGpugqm9fobBVg/iioE8kueXrOHdRDe36FAY7SnE9xXLVeYCoJR/gdrBEIHRC83Q==
+"@babel/generator@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5"
+  integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.14.5"
-    "@babel/helper-function-name" "^7.14.5"
-    "@babel/helper-member-expression-to-functions" "^7.15.0"
-    "@babel/helper-optimise-call-expression" "^7.14.5"
-    "@babel/helper-replace-supers" "^7.15.0"
-    "@babel/helper-split-export-declaration" "^7.14.5"
-
-"@babel/helper-create-regexp-features-plugin@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz#c7d5ac5e9cf621c26057722fb7a8a4c5889358c4"
-  integrity sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.14.5"
-    regexpu-core "^4.7.1"
+    "@babel/types" "^7.18.9"
+    "@jridgewell/gen-mapping" "^0.3.2"
+    jsesc "^2.5.1"
 
-"@babel/helper-define-polyfill-provider@^0.2.2":
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz#0525edec5094653a282688d34d846e4c75e9c0b6"
-  integrity sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==
+"@babel/helper-annotate-as-pure@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862"
+  integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==
   dependencies:
-    "@babel/helper-compilation-targets" "^7.13.0"
-    "@babel/helper-module-imports" "^7.12.13"
-    "@babel/helper-plugin-utils" "^7.13.0"
-    "@babel/traverse" "^7.13.0"
-    debug "^4.1.1"
-    lodash.debounce "^4.0.8"
-    resolve "^1.14.2"
-    semver "^6.1.2"
+    "@babel/types" "^7.16.7"
 
-"@babel/helper-explode-assignable-expression@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.14.5.tgz#8aa72e708205c7bb643e45c73b4386cdf2a1f645"
-  integrity sha512-Htb24gnGJdIGT4vnRKMdoXiOIlqOLmdiUYpAQ0mYfgVT/GDm8GOYhgi4GL+hMKrkiPRohO4ts34ELFsGAPQLDQ==
+"@babel/helper-annotate-as-pure@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
+  integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
   dependencies:
-    "@babel/types" "^7.14.5"
+    "@babel/types" "^7.18.6"
 
-"@babel/helper-function-name@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz#89e2c474972f15d8e233b52ee8c480e2cfcd50c4"
-  integrity sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz#acd4edfd7a566d1d51ea975dff38fd52906981bb"
+  integrity sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==
   dependencies:
-    "@babel/helper-get-function-arity" "^7.14.5"
-    "@babel/template" "^7.14.5"
-    "@babel/types" "^7.14.5"
+    "@babel/helper-explode-assignable-expression" "^7.18.6"
+    "@babel/types" "^7.18.9"
 
-"@babel/helper-get-function-arity@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz#25fbfa579b0937eee1f3b805ece4ce398c431815"
-  integrity sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==
+"@babel/helper-compilation-targets@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b"
+  integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==
   dependencies:
-    "@babel/types" "^7.14.5"
-
-"@babel/helper-hoist-variables@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz#e0dd27c33a78e577d7c8884916a3e7ef1f7c7f8d"
-  integrity sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==
-  dependencies:
-    "@babel/types" "^7.14.5"
+    "@babel/compat-data" "^7.16.4"
+    "@babel/helper-validator-option" "^7.16.7"
+    browserslist "^4.17.5"
+    semver "^6.3.0"
 
-"@babel/helper-member-expression-to-functions@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz#0ddaf5299c8179f27f37327936553e9bba60990b"
-  integrity sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==
+"@babel/helper-compilation-targets@^7.17.7":
+  version "7.17.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46"
+  integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w==
   dependencies:
-    "@babel/types" "^7.15.0"
+    "@babel/compat-data" "^7.17.7"
+    "@babel/helper-validator-option" "^7.16.7"
+    browserslist "^4.17.5"
+    semver "^6.3.0"
 
-"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz#6d1a44df6a38c957aa7c312da076429f11b422f3"
-  integrity sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==
-  dependencies:
-    "@babel/types" "^7.14.5"
-
-"@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz#679275581ea056373eddbe360e1419ef23783b08"
-  integrity sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==
-  dependencies:
-    "@babel/helper-module-imports" "^7.14.5"
-    "@babel/helper-replace-supers" "^7.15.0"
-    "@babel/helper-simple-access" "^7.14.8"
-    "@babel/helper-split-export-declaration" "^7.14.5"
-    "@babel/helper-validator-identifier" "^7.14.9"
-    "@babel/template" "^7.14.5"
-    "@babel/traverse" "^7.15.0"
-    "@babel/types" "^7.15.0"
-
-"@babel/helper-optimise-call-expression@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz#f27395a8619e0665b3f0364cddb41c25d71b499c"
-  integrity sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==
+"@babel/helper-compilation-targets@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
+  integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
   dependencies:
-    "@babel/types" "^7.14.5"
-
-"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
-  integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
+    "@babel/compat-data" "^7.18.8"
+    "@babel/helper-validator-option" "^7.18.6"
+    browserslist "^4.20.2"
+    semver "^6.3.0"
 
-"@babel/helper-remap-async-to-generator@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.14.5.tgz#51439c913612958f54a987a4ffc9ee587a2045d6"
-  integrity sha512-rLQKdQU+HYlxBwQIj8dk4/0ENOUEhA/Z0l4hN8BexpvmSMN9oA9EagjnhnDpNsRdWCfjwa4mn/HyBXO9yhQP6A==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.14.5"
-    "@babel/helper-wrap-function" "^7.14.5"
-    "@babel/types" "^7.14.5"
+"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz#d802ee16a64a9e824fcbf0a2ffc92f19d58550ce"
+  integrity sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.18.6"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-function-name" "^7.18.9"
+    "@babel/helper-member-expression-to-functions" "^7.18.9"
+    "@babel/helper-optimise-call-expression" "^7.18.6"
+    "@babel/helper-replace-supers" "^7.18.9"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+
+"@babel/helper-create-regexp-features-plugin@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz#0cb82b9bac358eb73bfbd73985a776bfa6b14d48"
+  integrity sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.16.7"
+    regexpu-core "^4.7.1"
 
-"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz#ace07708f5bf746bf2e6ba99572cce79b5d4e7f4"
-  integrity sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==
+"@babel/helper-create-regexp-features-plugin@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.18.6.tgz#3e35f4e04acbbf25f1b3534a657610a000543d3c"
+  integrity sha512-7LcpH1wnQLGrI+4v+nPp+zUvIkF9x0ddv1Hkdue10tg3gmRnLy97DXh4STiOf1qeIInyD69Qv5kKSZzKD8B/7A==
   dependencies:
-    "@babel/helper-member-expression-to-functions" "^7.15.0"
-    "@babel/helper-optimise-call-expression" "^7.14.5"
-    "@babel/traverse" "^7.15.0"
-    "@babel/types" "^7.15.0"
+    "@babel/helper-annotate-as-pure" "^7.18.6"
+    regexpu-core "^5.1.0"
 
-"@babel/helper-simple-access@^7.14.8":
-  version "7.14.8"
-  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz#82e1fec0644a7e775c74d305f212c39f8fe73924"
-  integrity sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==
+"@babel/helper-define-polyfill-provider@^0.3.1", "@babel/helper-define-polyfill-provider@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz#bd10d0aca18e8ce012755395b05a79f45eca5073"
+  integrity sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==
   dependencies:
-    "@babel/types" "^7.14.8"
+    "@babel/helper-compilation-targets" "^7.17.7"
+    "@babel/helper-plugin-utils" "^7.16.7"
+    debug "^4.1.1"
+    lodash.debounce "^4.0.8"
+    resolve "^1.14.2"
+    semver "^6.1.2"
 
-"@babel/helper-skip-transparent-expression-wrappers@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.14.5.tgz#96f486ac050ca9f44b009fbe5b7d394cab3a0ee4"
-  integrity sha512-dmqZB7mrb94PZSAOYtr+ZN5qt5owZIAgqtoTuqiFbHFtxgEcmQlRJVI+bO++fciBunXtB6MK7HrzrfcAzIz2NQ==
-  dependencies:
-    "@babel/types" "^7.14.5"
+"@babel/helper-environment-visitor@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7"
+  integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==
+  dependencies:
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-environment-visitor@^7.18.6", "@babel/helper-environment-visitor@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
+  integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
+
+"@babel/helper-explode-assignable-expression@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz#41f8228ef0a6f1a036b8dfdfec7ce94f9a6bc096"
+  integrity sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-function-name@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f"
+  integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.16.7"
+    "@babel/template" "^7.16.7"
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-function-name@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0"
+  integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
+  dependencies:
+    "@babel/template" "^7.18.6"
+    "@babel/types" "^7.18.9"
+
+"@babel/helper-get-function-arity@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419"
+  integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==
+  dependencies:
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-hoist-variables@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246"
+  integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==
+  dependencies:
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-hoist-variables@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
+  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-member-expression-to-functions@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
+  integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==
+  dependencies:
+    "@babel/types" "^7.18.9"
+
+"@babel/helper-module-imports@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
+  integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==
+  dependencies:
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-module-imports@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
+  integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-module-transforms@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41"
+  integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==
+  dependencies:
+    "@babel/helper-environment-visitor" "^7.16.7"
+    "@babel/helper-module-imports" "^7.16.7"
+    "@babel/helper-simple-access" "^7.16.7"
+    "@babel/helper-split-export-declaration" "^7.16.7"
+    "@babel/helper-validator-identifier" "^7.16.7"
+    "@babel/template" "^7.16.7"
+    "@babel/traverse" "^7.16.7"
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712"
+  integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==
+  dependencies:
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-module-imports" "^7.18.6"
+    "@babel/helper-simple-access" "^7.18.6"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/helper-validator-identifier" "^7.18.6"
+    "@babel/template" "^7.18.6"
+    "@babel/traverse" "^7.18.9"
+    "@babel/types" "^7.18.9"
+
+"@babel/helper-optimise-call-expression@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe"
+  integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
+  integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
+
+"@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
+  integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
+
+"@babel/helper-remap-async-to-generator@^7.18.6":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519"
+  integrity sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.18.6"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-wrap-function" "^7.18.9"
+    "@babel/types" "^7.18.9"
+
+"@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6"
+  integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==
+  dependencies:
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-member-expression-to-functions" "^7.18.9"
+    "@babel/helper-optimise-call-expression" "^7.18.6"
+    "@babel/traverse" "^7.18.9"
+    "@babel/types" "^7.18.9"
+
+"@babel/helper-simple-access@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7"
+  integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==
+  dependencies:
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-simple-access@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
+  integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-skip-transparent-expression-wrappers@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz#778d87b3a758d90b471e7b9918f34a9a02eb5818"
+  integrity sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==
+  dependencies:
+    "@babel/types" "^7.18.9"
+
+"@babel/helper-split-export-declaration@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b"
+  integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==
+  dependencies:
+    "@babel/types" "^7.16.7"
+
+"@babel/helper-split-export-declaration@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
+  integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
+  dependencies:
+    "@babel/types" "^7.18.6"
+
+"@babel/helper-validator-identifier@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
+  integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
+
+"@babel/helper-validator-identifier@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
+  integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
+
+"@babel/helper-validator-option@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23"
+  integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==
+
+"@babel/helper-validator-option@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
+  integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
+
+"@babel/helper-wrap-function@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.18.9.tgz#ae1feddc6ebbaa2fd79346b77821c3bd73a39646"
+  integrity sha512-cG2ru3TRAL6a60tfQflpEfs4ldiPwF6YW3zfJiRgmoFVIaC1vGnBBgatfec+ZUziPHkHSaXAuEck3Cdkf3eRpQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.18.9"
+    "@babel/template" "^7.18.6"
+    "@babel/traverse" "^7.18.9"
+    "@babel/types" "^7.18.9"
+
+"@babel/helpers@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc"
+  integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==
+  dependencies:
+    "@babel/template" "^7.16.7"
+    "@babel/traverse" "^7.16.7"
+    "@babel/types" "^7.16.7"
+
+"@babel/helpers@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9"
+  integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==
+  dependencies:
+    "@babel/template" "^7.18.6"
+    "@babel/traverse" "^7.18.9"
+    "@babel/types" "^7.18.9"
+
+"@babel/highlight@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b"
+  integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.16.7"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
 
-"@babel/helper-split-export-declaration@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz#22b23a54ef51c2b7605d851930c1976dd0bc693a"
-  integrity sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==
+"@babel/highlight@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
+  integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
   dependencies:
-    "@babel/types" "^7.14.5"
-
-"@babel/helper-validator-identifier@^7.14.5", "@babel/helper-validator-identifier@^7.14.9":
-  version "7.14.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz#6654d171b2024f6d8ee151bf2509699919131d48"
-  integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==
-
-"@babel/helper-validator-option@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
-  integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==
+    "@babel/helper-validator-identifier" "^7.18.6"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
 
-"@babel/helper-wrap-function@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.14.5.tgz#5919d115bf0fe328b8a5d63bcb610f51601f2bff"
-  integrity sha512-YEdjTCq+LNuNS1WfxsDCNpgXkJaIyqco6DAelTUjT4f2KIWC1nBcaCaSdHTBqQVLnTBexBcVcFhLSU1KnYuePQ==
-  dependencies:
-    "@babel/helper-function-name" "^7.14.5"
-    "@babel/template" "^7.14.5"
-    "@babel/traverse" "^7.14.5"
-    "@babel/types" "^7.14.5"
+"@babel/parser@^7.0.0-beta.54", "@babel/parser@^7.16.7", "@babel/parser@^7.16.8":
+  version "7.16.8"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17"
+  integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==
 
-"@babel/helpers@^7.14.8":
-  version "7.15.3"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.3.tgz#c96838b752b95dcd525b4e741ed40bb1dc2a1357"
-  integrity sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==
-  dependencies:
-    "@babel/template" "^7.14.5"
-    "@babel/traverse" "^7.15.0"
-    "@babel/types" "^7.15.0"
+"@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
+  integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
 
-"@babel/highlight@^7.10.4", "@babel/highlight@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9"
-  integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz#da5b8f9a580acdfbe53494dba45ea389fb09a4d2"
+  integrity sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==
   dependencies:
-    "@babel/helper-validator-identifier" "^7.14.5"
-    chalk "^2.0.0"
-    js-tokens "^4.0.0"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/parser@^7.0.0-beta.54", "@babel/parser@^7.14.5", "@babel/parser@^7.15.0":
-  version "7.15.3"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.3.tgz#3416d9bea748052cfcb63dbcc27368105b1ed862"
-  integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==
-
-"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e"
-  integrity sha512-ZoJS2XCKPBfTmL122iP6NM9dOg+d4lc9fFk3zxc8iDjvt8Pk4+TlsHSKhIPf6X+L5ORCdBzqMZDjL/WHj7WknQ==
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz#a11af19aa373d68d561f08e0a57242350ed0ec50"
+  integrity sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
-    "@babel/plugin-proposal-optional-chaining" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
+    "@babel/plugin-proposal-optional-chaining" "^7.18.9"
 
-"@babel/plugin-proposal-async-generator-functions@^7.14.9":
-  version "7.14.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.9.tgz#7028dc4fa21dc199bbacf98b39bab1267d0eaf9a"
-  integrity sha512-d1lnh+ZnKrFKwtTYdw320+sQWCTwgkB9fmUhNXRADA4akR6wLjaruSGnIEUjpt9HCOwTr4ynFTKu19b7rFRpmw==
+"@babel/plugin-proposal-async-generator-functions@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz#aedac81e6fc12bb643374656dd5f2605bf743d17"
+  integrity sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-remap-async-to-generator" "^7.14.5"
+    "@babel/helper-environment-visitor" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/helper-remap-async-to-generator" "^7.18.6"
     "@babel/plugin-syntax-async-generators" "^7.8.4"
 
-"@babel/plugin-proposal-class-properties@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz#40d1ee140c5b1e31a350f4f5eed945096559b42e"
-  integrity sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==
+"@babel/plugin-proposal-class-properties@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3"
+  integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-class-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-proposal-class-static-block@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.14.5.tgz#158e9e10d449c3849ef3ecde94a03d9f1841b681"
-  integrity sha512-KBAH5ksEnYHCegqseI5N9skTdxgJdmDoAOc0uXa+4QMYKeZD0w5IARh4FMlTNtaHhbB8v+KzMdTgxMMzsIy6Yg==
+"@babel/plugin-proposal-class-static-block@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz#8aa81d403ab72d3962fc06c26e222dacfc9b9020"
+  integrity sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-class-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-class-static-block" "^7.14.5"
 
-"@babel/plugin-proposal-dynamic-import@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz#0c6617df461c0c1f8fff3b47cd59772360101d2c"
-  integrity sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==
+"@babel/plugin-proposal-decorators@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.18.9.tgz#d09d41ffc74af8499d2ac706ed0dbd5474711665"
+  integrity sha512-KD7zDNaD14CRpjQjVbV4EnH9lsKYlcpUrhZH37ei2IY+AlXrfAPy5pTmRUE4X6X1k8EsKXPraykxeaogqQvSGA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-class-features-plugin" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-replace-supers" "^7.18.9"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/plugin-syntax-decorators" "^7.18.6"
+
+"@babel/plugin-proposal-dynamic-import@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz#72bcf8d408799f547d759298c3c27c7e7faa4d94"
+  integrity sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-dynamic-import" "^7.8.3"
 
-"@babel/plugin-proposal-export-namespace-from@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz#dbad244310ce6ccd083072167d8cea83a52faf76"
-  integrity sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==
+"@babel/plugin-proposal-export-namespace-from@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz#5f7313ab348cdb19d590145f9247540e94761203"
+  integrity sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
     "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
 
-"@babel/plugin-proposal-json-strings@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz#38de60db362e83a3d8c944ac858ddf9f0c2239eb"
-  integrity sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==
+"@babel/plugin-proposal-json-strings@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz#7e8788c1811c393aff762817e7dbf1ebd0c05f0b"
+  integrity sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-json-strings" "^7.8.3"
 
-"@babel/plugin-proposal-logical-assignment-operators@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz#6e6229c2a99b02ab2915f82571e0cc646a40c738"
-  integrity sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==
+"@babel/plugin-proposal-logical-assignment-operators@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz#8148cbb350483bf6220af06fa6db3690e14b2e23"
+  integrity sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
     "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
 
-"@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz#ee38589ce00e2cc59b299ec3ea406fcd3a0fdaf6"
-  integrity sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1"
+  integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
 
-"@babel/plugin-proposal-numeric-separator@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz#83631bf33d9a51df184c2102a069ac0c58c05f18"
-  integrity sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==
+"@babel/plugin-proposal-numeric-separator@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75"
+  integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-numeric-separator" "^7.10.4"
 
-"@babel/plugin-proposal-object-rest-spread@^7.14.7":
-  version "7.14.7"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz#5920a2b3df7f7901df0205974c0641b13fd9d363"
-  integrity sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==
+"@babel/plugin-proposal-object-rest-spread@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz#f9434f6beb2c8cae9dfcf97d2a5941bbbf9ad4e7"
+  integrity sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==
   dependencies:
-    "@babel/compat-data" "^7.14.7"
-    "@babel/helper-compilation-targets" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/compat-data" "^7.18.8"
+    "@babel/helper-compilation-targets" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.18.9"
     "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
-    "@babel/plugin-transform-parameters" "^7.14.5"
+    "@babel/plugin-transform-parameters" "^7.18.8"
 
-"@babel/plugin-proposal-optional-catch-binding@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz#939dd6eddeff3a67fdf7b3f044b5347262598c3c"
-  integrity sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==
+"@babel/plugin-proposal-optional-catch-binding@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz#f9400d0e6a3ea93ba9ef70b09e72dd6da638a2cb"
+  integrity sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
 
-"@babel/plugin-proposal-optional-chaining@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz#fa83651e60a360e3f13797eef00b8d519695b603"
-  integrity sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==
+"@babel/plugin-proposal-optional-chaining@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz#e8e8fe0723f2563960e4bf5e9690933691915993"
+  integrity sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
     "@babel/plugin-syntax-optional-chaining" "^7.8.3"
 
-"@babel/plugin-proposal-private-methods@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz#37446495996b2945f30f5be5b60d5e2aa4f5792d"
-  integrity sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==
+"@babel/plugin-proposal-private-methods@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea"
+  integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-class-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-proposal-private-property-in-object@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.14.5.tgz#9f65a4d0493a940b4c01f8aa9d3f1894a587f636"
-  integrity sha512-62EyfyA3WA0mZiF2e2IV9mc9Ghwxcg8YTu8BS4Wss4Y3PY725OmS9M0qLORbJwLqFtGh+jiE4wAmocK2CTUK2Q==
+"@babel/plugin-proposal-private-property-in-object@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz#a64137b232f0aca3733a67eb1a144c192389c503"
+  integrity sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.14.5"
-    "@babel/helper-create-class-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-annotate-as-pure" "^7.18.6"
+    "@babel/helper-create-class-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
     "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
 
-"@babel/plugin-proposal-unicode-property-regex@^7.14.5", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz#0f95ee0e757a5d647f378daa0eca7e93faa8bbe8"
-  integrity sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==
+"@babel/plugin-proposal-unicode-property-regex@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e"
+  integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2"
+  integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.16.7"
+    "@babel/helper-plugin-utils" "^7.16.7"
 
 "@babel/plugin-syntax-async-generators@^7.8.4":
   version "7.8.4"
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
 
+"@babel/plugin-syntax-decorators@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.18.6.tgz#2e45af22835d0b0f8665da2bfd4463649ce5dbc1"
+  integrity sha512-fqyLgjcxf/1yhyZ6A+yo1u9gJ7eleFQod2lkaUsF9DQ7sbbY3Ligym3L0+I2c0WmqNKDpoD9UTb1AKP3qRMOAQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.6"
+
 "@babel/plugin-syntax-dynamic-import@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3"
   dependencies:
     "@babel/helper-plugin-utils" "^7.8.3"
 
+"@babel/plugin-syntax-import-assertions@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz#cd6190500a4fa2fe31990a963ffab4b63e4505e4"
+  integrity sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.6"
+
 "@babel/plugin-syntax-json-strings@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
     "@babel/helper-plugin-utils" "^7.8.0"
 
 "@babel/plugin-syntax-jsx@^7":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz#000e2e25d8673cce49300517a3eda44c263e4201"
-  integrity sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665"
+  integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.16.7"
 
 "@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
   version "7.10.4"
   dependencies:
     "@babel/helper-plugin-utils" "^7.14.5"
 
-"@babel/plugin-syntax-typescript@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz#b82c6ce471b165b5ce420cf92914d6fb46225716"
-  integrity sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==
+"@babel/plugin-syntax-typescript@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285"
+  integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-arrow-functions@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz#f7187d9588a768dd080bf4c9ffe117ea62f7862a"
-  integrity sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==
+"@babel/plugin-transform-arrow-functions@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz#19063fcf8771ec7b31d742339dac62433d0611fe"
+  integrity sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-async-to-generator@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz#72c789084d8f2094acb945633943ef8443d39e67"
-  integrity sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==
+"@babel/plugin-transform-async-to-generator@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz#ccda3d1ab9d5ced5265fdb13f1882d5476c71615"
+  integrity sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==
   dependencies:
-    "@babel/helper-module-imports" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-remap-async-to-generator" "^7.14.5"
+    "@babel/helper-module-imports" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/helper-remap-async-to-generator" "^7.18.6"
 
-"@babel/plugin-transform-block-scoped-functions@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz#e48641d999d4bc157a67ef336aeb54bc44fd3ad4"
-  integrity sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==
+"@babel/plugin-transform-block-scoped-functions@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz#9187bf4ba302635b9d70d986ad70f038726216a8"
+  integrity sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-block-scoping@^7.14.5":
-  version "7.15.3"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz#94c81a6e2fc230bcce6ef537ac96a1e4d2b3afaf"
-  integrity sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==
+"@babel/plugin-transform-block-scoping@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz#f9b7e018ac3f373c81452d6ada8bd5a18928926d"
+  integrity sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-classes@^7.14.9":
-  version "7.14.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.14.9.tgz#2a391ffb1e5292710b00f2e2c210e1435e7d449f"
-  integrity sha512-NfZpTcxU3foGWbl4wxmZ35mTsYJy8oQocbeIMoDAGGFarAmSQlL+LWMkDx/tj6pNotpbX3rltIA4dprgAPOq5A==
+"@babel/plugin-transform-classes@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz#90818efc5b9746879b869d5ce83eb2aa48bbc3da"
+  integrity sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==
   dependencies:
-    "@babel/helper-annotate-as-pure" "^7.14.5"
-    "@babel/helper-function-name" "^7.14.5"
-    "@babel/helper-optimise-call-expression" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-replace-supers" "^7.14.5"
-    "@babel/helper-split-export-declaration" "^7.14.5"
+    "@babel/helper-annotate-as-pure" "^7.18.6"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-function-name" "^7.18.9"
+    "@babel/helper-optimise-call-expression" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-replace-supers" "^7.18.9"
+    "@babel/helper-split-export-declaration" "^7.18.6"
     globals "^11.1.0"
 
-"@babel/plugin-transform-computed-properties@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz#1b9d78987420d11223d41195461cc43b974b204f"
-  integrity sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==
+"@babel/plugin-transform-computed-properties@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz#2357a8224d402dad623caf6259b611e56aec746e"
+  integrity sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-destructuring@^7.14.7":
-  version "7.14.7"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz#0ad58ed37e23e22084d109f185260835e5557576"
-  integrity sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==
+"@babel/plugin-transform-destructuring@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz#68906549c021cb231bee1db21d3b5b095f8ee292"
+  integrity sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-dotall-regex@^7.14.5", "@babel/plugin-transform-dotall-regex@^7.4.4":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz#2f6bf76e46bdf8043b4e7e16cf24532629ba0c7a"
-  integrity sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==
+"@babel/plugin-transform-dotall-regex@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz#b286b3e7aae6c7b861e45bed0a2fafd6b1a4fef8"
+  integrity sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-duplicate-keys@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz#365a4844881bdf1501e3a9f0270e7f0f91177954"
-  integrity sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==
+"@babel/plugin-transform-dotall-regex@^7.4.4":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241"
+  integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-regexp-features-plugin" "^7.16.7"
+    "@babel/helper-plugin-utils" "^7.16.7"
 
-"@babel/plugin-transform-exponentiation-operator@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz#5154b8dd6a3dfe6d90923d61724bd3deeb90b493"
-  integrity sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==
+"@babel/plugin-transform-duplicate-keys@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz#687f15ee3cdad6d85191eb2a372c4528eaa0ae0e"
+  integrity sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==
   dependencies:
-    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-for-of@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.14.5.tgz#dae384613de8f77c196a8869cbf602a44f7fc0eb"
-  integrity sha512-CfmqxSUZzBl0rSjpoQSFoR9UEj3HzbGuGNL21/iFTmjb5gFggJp3ph0xR1YBhexmLoKRHzgxuFvty2xdSt6gTA==
+"@babel/plugin-transform-exponentiation-operator@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz#421c705f4521888c65e91fdd1af951bfefd4dacd"
+  integrity sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-function-name@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz#e81c65ecb900746d7f31802f6bed1f52d915d6f2"
-  integrity sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==
+"@babel/plugin-transform-for-of@^7.18.8":
+  version "7.18.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1"
+  integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==
   dependencies:
-    "@babel/helper-function-name" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-literals@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz#41d06c7ff5d4d09e3cf4587bd3ecf3930c730f78"
-  integrity sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==
+"@babel/plugin-transform-function-name@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz#cc354f8234e62968946c61a46d6365440fc764e0"
+  integrity sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-compilation-targets" "^7.18.9"
+    "@babel/helper-function-name" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-member-expression-literals@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz#b39cd5212a2bf235a617d320ec2b48bcc091b8a7"
-  integrity sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==
+"@babel/plugin-transform-literals@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz#72796fdbef80e56fba3c6a699d54f0de557444bc"
+  integrity sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.9"
 
-"@babel/plugin-transform-modules-amd@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz#4fd9ce7e3411cb8b83848480b7041d83004858f7"
-  integrity sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==
+"@babel/plugin-transform-member-expression-literals@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz#ac9fdc1a118620ac49b7e7a5d2dc177a1bfee88e"
+  integrity sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==
   dependencies:
-    "@babel/helper-module-transforms" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    babel-plugin-dynamic-import-node "^2.3.3"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-modules-commonjs@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.0.tgz#3305896e5835f953b5cdb363acd9e8c2219a5281"
-  integrity sha512-3H/R9s8cXcOGE8kgMlmjYYC9nqr5ELiPkJn4q0mypBrjhYQoc+5/Maq69vV4xRPWnkzZuwJPf5rArxpB/35Cig==
+"@babel/plugin-transform-modules-amd@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz#8c91f8c5115d2202f277549848874027d7172d21"
+  integrity sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==
   dependencies:
-    "@babel/helper-module-transforms" "^7.15.0"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-simple-access" "^7.14.8"
+    "@babel/helper-module-transforms" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
     babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-modules-systemjs@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.14.5.tgz#c75342ef8b30dcde4295d3401aae24e65638ed29"
-  integrity sha512-mNMQdvBEE5DcMQaL5LbzXFMANrQjd2W7FPzg34Y4yEz7dBgdaC+9B84dSO+/1Wba98zoDbInctCDo4JGxz1VYA==
+"@babel/plugin-transform-modules-commonjs@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz#afd243afba166cca69892e24a8fd8c9f2ca87883"
+  integrity sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==
   dependencies:
-    "@babel/helper-hoist-variables" "^7.14.5"
-    "@babel/helper-module-transforms" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-validator-identifier" "^7.14.5"
+    "@babel/helper-module-transforms" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/helper-simple-access" "^7.18.6"
     babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-modules-umd@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz#fb662dfee697cce274a7cda525190a79096aa6e0"
-  integrity sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==
+"@babel/plugin-transform-modules-systemjs@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz#545df284a7ac6a05125e3e405e536c5853099a06"
+  integrity sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==
   dependencies:
-    "@babel/helper-module-transforms" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-named-capturing-groups-regex@^7.14.9":
-  version "7.14.9"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz#c68f5c5d12d2ebaba3762e57c2c4f6347a46e7b2"
-  integrity sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==
-  dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.14.5"
-
-"@babel/plugin-transform-new-target@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz#31bdae8b925dc84076ebfcd2a9940143aed7dbf8"
-  integrity sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-object-super@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz#d0b5faeac9e98597a161a9cf78c527ed934cdc45"
-  integrity sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-replace-supers" "^7.14.5"
-
-"@babel/plugin-transform-parameters@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.14.5.tgz#49662e86a1f3ddccac6363a7dfb1ff0a158afeb3"
-  integrity sha512-Tl7LWdr6HUxTmzQtzuU14SqbgrSKmaR77M0OKyq4njZLQTPfOvzblNKyNkGwOfEFCEx7KeYHQHDI0P3F02IVkA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-property-literals@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz#0ddbaa1f83db3606f1cdf4846fa1dfb473458b34"
-  integrity sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-
-"@babel/plugin-transform-regenerator@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz#9676fd5707ed28f522727c5b3c0aa8544440b04f"
-  integrity sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==
-  dependencies:
-    regenerator-transform "^0.14.2"
-
-"@babel/plugin-transform-reserved-words@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz#c44589b661cfdbef8d4300dcc7469dffa92f8304"
-  integrity sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-hoist-variables" "^7.18.6"
+    "@babel/helper-module-transforms" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-validator-identifier" "^7.18.6"
+    babel-plugin-dynamic-import-node "^2.3.3"
 
-"@babel/plugin-transform-runtime@^7.14.5":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz#d3aa650d11678ca76ce294071fda53d7804183b3"
-  integrity sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==
+"@babel/plugin-transform-modules-umd@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz#81d3832d6034b75b54e62821ba58f28ed0aab4b9"
+  integrity sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==
   dependencies:
-    "@babel/helper-module-imports" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    babel-plugin-polyfill-corejs2 "^0.2.2"
-    babel-plugin-polyfill-corejs3 "^0.2.2"
-    babel-plugin-polyfill-regenerator "^0.2.2"
-    semver "^6.3.0"
+    "@babel/helper-module-transforms" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-shorthand-properties@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz#97f13855f1409338d8cadcbaca670ad79e091a58"
-  integrity sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==
+"@babel/plugin-transform-named-capturing-groups-regex@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.18.6.tgz#c89bfbc7cc6805d692f3a49bc5fc1b630007246d"
+  integrity sha512-UmEOGF8XgaIqD74bC8g7iV3RYj8lMf0Bw7NJzvnS9qQhM4mg+1WHKotUIdjxgD2RGrgFLZZPCFPFj3P/kVDYhg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-spread@^7.14.6":
-  version "7.14.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz#6bd40e57fe7de94aa904851963b5616652f73144"
-  integrity sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==
+"@babel/plugin-transform-new-target@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz#d128f376ae200477f37c4ddfcc722a8a1b3246a8"
+  integrity sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-skip-transparent-expression-wrappers" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-sticky-regex@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz#5b617542675e8b7761294381f3c28c633f40aeb9"
-  integrity sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==
+"@babel/plugin-transform-object-super@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz#fb3c6ccdd15939b6ff7939944b51971ddc35912c"
+  integrity sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/helper-replace-supers" "^7.18.6"
 
-"@babel/plugin-transform-template-literals@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz#a5f2bc233937d8453885dc736bdd8d9ffabf3d93"
-  integrity sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==
+"@babel/plugin-transform-parameters@^7.18.8":
+  version "7.18.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a"
+  integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-typeof-symbol@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz#39af2739e989a2bd291bf6b53f16981423d457d4"
-  integrity sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==
+"@babel/plugin-transform-property-literals@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz#e22498903a483448e94e032e9bbb9c5ccbfc93a3"
+  integrity sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-typescript@^7.14.6", "@babel/plugin-transform-typescript@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.0.tgz#553f230b9d5385018716586fc48db10dd228eb7e"
-  integrity sha512-WIIEazmngMEEHDaPTx0IZY48SaAmjVWe3TRSX7cmJXn0bEv9midFzAjxiruOWYIVf5iQ10vFx7ASDpgEO08L5w==
+"@babel/plugin-transform-regenerator@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz#585c66cb84d4b4bf72519a34cfce761b8676ca73"
+  integrity sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==
   dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.15.0"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/plugin-syntax-typescript" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    regenerator-transform "^0.15.0"
 
-"@babel/plugin-transform-unicode-escapes@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz#9d4bd2a681e3c5d7acf4f57fa9e51175d91d0c6b"
-  integrity sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==
+"@babel/plugin-transform-reserved-words@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz#b1abd8ebf8edaa5f7fe6bbb8d2133d23b6a6f76a"
+  integrity sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-plugin-utils" "^7.18.6"
 
-"@babel/plugin-transform-unicode-regex@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz#4cd09b6c8425dd81255c7ceb3fb1836e7414382e"
-  integrity sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==
+"@babel/plugin-transform-runtime@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.9.tgz#d9e4b1b25719307bfafbf43065ed7fb3a83adb8f"
+  integrity sha512-wS8uJwBt7/b/mzE13ktsJdmS4JP/j7PQSaADtnb4I2wL0zK51MQ0pmF8/Jy0wUIS96fr+fXT6S/ifiPXnvrlSg==
   dependencies:
-    "@babel/helper-create-regexp-features-plugin" "^7.14.5"
-    "@babel/helper-plugin-utils" "^7.14.5"
+    "@babel/helper-module-imports" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    babel-plugin-polyfill-corejs2 "^0.3.1"
+    babel-plugin-polyfill-corejs3 "^0.5.2"
+    babel-plugin-polyfill-regenerator "^0.3.1"
+    semver "^6.3.0"
 
-"@babel/preset-env@7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.15.0.tgz#e2165bf16594c9c05e52517a194bf6187d6fe464"
-  integrity sha512-FhEpCNFCcWW3iZLg0L2NPE9UerdtsCR6ZcsGHUX6Om6kbCQeL5QZDqFDmeNHC6/fy6UH3jEge7K4qG5uC9In0Q==
-  dependencies:
-    "@babel/compat-data" "^7.15.0"
-    "@babel/helper-compilation-targets" "^7.15.0"
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-validator-option" "^7.14.5"
-    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.14.5"
-    "@babel/plugin-proposal-async-generator-functions" "^7.14.9"
-    "@babel/plugin-proposal-class-properties" "^7.14.5"
-    "@babel/plugin-proposal-class-static-block" "^7.14.5"
-    "@babel/plugin-proposal-dynamic-import" "^7.14.5"
-    "@babel/plugin-proposal-export-namespace-from" "^7.14.5"
-    "@babel/plugin-proposal-json-strings" "^7.14.5"
-    "@babel/plugin-proposal-logical-assignment-operators" "^7.14.5"
-    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.14.5"
-    "@babel/plugin-proposal-numeric-separator" "^7.14.5"
-    "@babel/plugin-proposal-object-rest-spread" "^7.14.7"
-    "@babel/plugin-proposal-optional-catch-binding" "^7.14.5"
-    "@babel/plugin-proposal-optional-chaining" "^7.14.5"
-    "@babel/plugin-proposal-private-methods" "^7.14.5"
-    "@babel/plugin-proposal-private-property-in-object" "^7.14.5"
-    "@babel/plugin-proposal-unicode-property-regex" "^7.14.5"
+"@babel/plugin-transform-shorthand-properties@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz#6d6df7983d67b195289be24909e3f12a8f664dc9"
+  integrity sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-transform-spread@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz#6ea7a6297740f381c540ac56caf75b05b74fb664"
+  integrity sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9"
+
+"@babel/plugin-transform-sticky-regex@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz#c6706eb2b1524028e317720339583ad0f444adcc"
+  integrity sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-transform-template-literals@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz#04ec6f10acdaa81846689d63fae117dd9c243a5e"
+  integrity sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.9"
+
+"@babel/plugin-transform-typeof-symbol@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz#c8cea68263e45addcd6afc9091429f80925762c0"
+  integrity sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.9"
+
+"@babel/plugin-transform-typescript@^7.18.6", "@babel/plugin-transform-typescript@^7.18.8":
+  version "7.18.8"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.8.tgz#303feb7a920e650f2213ef37b36bbf327e6fa5a0"
+  integrity sha512-p2xM8HI83UObjsZGofMV/EdYjamsDm6MoN3hXPYIT0+gxIoopE+B7rPYKAxfrz9K9PK7JafTTjqYC6qipLExYA==
+  dependencies:
+    "@babel/helper-create-class-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/plugin-syntax-typescript" "^7.18.6"
+
+"@babel/plugin-transform-unicode-escapes@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz#0d01fb7fb2243ae1c033f65f6e3b4be78db75f27"
+  integrity sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-transform-unicode-regex@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz#194317225d8c201bbae103364ffe9e2cea36cdca"
+  integrity sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==
+  dependencies:
+    "@babel/helper-create-regexp-features-plugin" "^7.18.6"
+    "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/preset-env@7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.18.9.tgz#9b3425140d724fbe590322017466580844c7eaff"
+  integrity sha512-75pt/q95cMIHWssYtyfjVlvI+QEZQThQbKvR9xH+F/Agtw/s4Wfc2V9Bwd/P39VtixB7oWxGdH4GteTTwYJWMg==
+  dependencies:
+    "@babel/compat-data" "^7.18.8"
+    "@babel/helper-compilation-targets" "^7.18.9"
+    "@babel/helper-plugin-utils" "^7.18.9"
+    "@babel/helper-validator-option" "^7.18.6"
+    "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6"
+    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9"
+    "@babel/plugin-proposal-async-generator-functions" "^7.18.6"
+    "@babel/plugin-proposal-class-properties" "^7.18.6"
+    "@babel/plugin-proposal-class-static-block" "^7.18.6"
+    "@babel/plugin-proposal-dynamic-import" "^7.18.6"
+    "@babel/plugin-proposal-export-namespace-from" "^7.18.9"
+    "@babel/plugin-proposal-json-strings" "^7.18.6"
+    "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9"
+    "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6"
+    "@babel/plugin-proposal-numeric-separator" "^7.18.6"
+    "@babel/plugin-proposal-object-rest-spread" "^7.18.9"
+    "@babel/plugin-proposal-optional-catch-binding" "^7.18.6"
+    "@babel/plugin-proposal-optional-chaining" "^7.18.9"
+    "@babel/plugin-proposal-private-methods" "^7.18.6"
+    "@babel/plugin-proposal-private-property-in-object" "^7.18.6"
+    "@babel/plugin-proposal-unicode-property-regex" "^7.18.6"
     "@babel/plugin-syntax-async-generators" "^7.8.4"
     "@babel/plugin-syntax-class-properties" "^7.12.13"
     "@babel/plugin-syntax-class-static-block" "^7.14.5"
     "@babel/plugin-syntax-dynamic-import" "^7.8.3"
     "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+    "@babel/plugin-syntax-import-assertions" "^7.18.6"
     "@babel/plugin-syntax-json-strings" "^7.8.3"
     "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
     "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
     "@babel/plugin-syntax-optional-chaining" "^7.8.3"
     "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
     "@babel/plugin-syntax-top-level-await" "^7.14.5"
-    "@babel/plugin-transform-arrow-functions" "^7.14.5"
-    "@babel/plugin-transform-async-to-generator" "^7.14.5"
-    "@babel/plugin-transform-block-scoped-functions" "^7.14.5"
-    "@babel/plugin-transform-block-scoping" "^7.14.5"
-    "@babel/plugin-transform-classes" "^7.14.9"
-    "@babel/plugin-transform-computed-properties" "^7.14.5"
-    "@babel/plugin-transform-destructuring" "^7.14.7"
-    "@babel/plugin-transform-dotall-regex" "^7.14.5"
-    "@babel/plugin-transform-duplicate-keys" "^7.14.5"
-    "@babel/plugin-transform-exponentiation-operator" "^7.14.5"
-    "@babel/plugin-transform-for-of" "^7.14.5"
-    "@babel/plugin-transform-function-name" "^7.14.5"
-    "@babel/plugin-transform-literals" "^7.14.5"
-    "@babel/plugin-transform-member-expression-literals" "^7.14.5"
-    "@babel/plugin-transform-modules-amd" "^7.14.5"
-    "@babel/plugin-transform-modules-commonjs" "^7.15.0"
-    "@babel/plugin-transform-modules-systemjs" "^7.14.5"
-    "@babel/plugin-transform-modules-umd" "^7.14.5"
-    "@babel/plugin-transform-named-capturing-groups-regex" "^7.14.9"
-    "@babel/plugin-transform-new-target" "^7.14.5"
-    "@babel/plugin-transform-object-super" "^7.14.5"
-    "@babel/plugin-transform-parameters" "^7.14.5"
-    "@babel/plugin-transform-property-literals" "^7.14.5"
-    "@babel/plugin-transform-regenerator" "^7.14.5"
-    "@babel/plugin-transform-reserved-words" "^7.14.5"
-    "@babel/plugin-transform-shorthand-properties" "^7.14.5"
-    "@babel/plugin-transform-spread" "^7.14.6"
-    "@babel/plugin-transform-sticky-regex" "^7.14.5"
-    "@babel/plugin-transform-template-literals" "^7.14.5"
-    "@babel/plugin-transform-typeof-symbol" "^7.14.5"
-    "@babel/plugin-transform-unicode-escapes" "^7.14.5"
-    "@babel/plugin-transform-unicode-regex" "^7.14.5"
-    "@babel/preset-modules" "^0.1.4"
-    "@babel/types" "^7.15.0"
-    babel-plugin-polyfill-corejs2 "^0.2.2"
-    babel-plugin-polyfill-corejs3 "^0.2.2"
-    babel-plugin-polyfill-regenerator "^0.2.2"
-    core-js-compat "^3.16.0"
+    "@babel/plugin-transform-arrow-functions" "^7.18.6"
+    "@babel/plugin-transform-async-to-generator" "^7.18.6"
+    "@babel/plugin-transform-block-scoped-functions" "^7.18.6"
+    "@babel/plugin-transform-block-scoping" "^7.18.9"
+    "@babel/plugin-transform-classes" "^7.18.9"
+    "@babel/plugin-transform-computed-properties" "^7.18.9"
+    "@babel/plugin-transform-destructuring" "^7.18.9"
+    "@babel/plugin-transform-dotall-regex" "^7.18.6"
+    "@babel/plugin-transform-duplicate-keys" "^7.18.9"
+    "@babel/plugin-transform-exponentiation-operator" "^7.18.6"
+    "@babel/plugin-transform-for-of" "^7.18.8"
+    "@babel/plugin-transform-function-name" "^7.18.9"
+    "@babel/plugin-transform-literals" "^7.18.9"
+    "@babel/plugin-transform-member-expression-literals" "^7.18.6"
+    "@babel/plugin-transform-modules-amd" "^7.18.6"
+    "@babel/plugin-transform-modules-commonjs" "^7.18.6"
+    "@babel/plugin-transform-modules-systemjs" "^7.18.9"
+    "@babel/plugin-transform-modules-umd" "^7.18.6"
+    "@babel/plugin-transform-named-capturing-groups-regex" "^7.18.6"
+    "@babel/plugin-transform-new-target" "^7.18.6"
+    "@babel/plugin-transform-object-super" "^7.18.6"
+    "@babel/plugin-transform-parameters" "^7.18.8"
+    "@babel/plugin-transform-property-literals" "^7.18.6"
+    "@babel/plugin-transform-regenerator" "^7.18.6"
+    "@babel/plugin-transform-reserved-words" "^7.18.6"
+    "@babel/plugin-transform-shorthand-properties" "^7.18.6"
+    "@babel/plugin-transform-spread" "^7.18.9"
+    "@babel/plugin-transform-sticky-regex" "^7.18.6"
+    "@babel/plugin-transform-template-literals" "^7.18.9"
+    "@babel/plugin-transform-typeof-symbol" "^7.18.9"
+    "@babel/plugin-transform-unicode-escapes" "^7.18.6"
+    "@babel/plugin-transform-unicode-regex" "^7.18.6"
+    "@babel/preset-modules" "^0.1.5"
+    "@babel/types" "^7.18.9"
+    babel-plugin-polyfill-corejs2 "^0.3.1"
+    babel-plugin-polyfill-corejs3 "^0.5.2"
+    babel-plugin-polyfill-regenerator "^0.3.1"
+    core-js-compat "^3.22.1"
     semver "^6.3.0"
 
-"@babel/preset-modules@^0.1.4":
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e"
-  integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==
+"@babel/preset-modules@^0.1.5":
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9"
+  integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==
   dependencies:
     "@babel/helper-plugin-utils" "^7.0.0"
     "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
     "@babel/types" "^7.4.4"
     esutils "^2.0.2"
 
-"@babel/preset-typescript@^7.14.5":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945"
-  integrity sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow==
+"@babel/preset-typescript@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399"
+  integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==
   dependencies:
-    "@babel/helper-plugin-utils" "^7.14.5"
-    "@babel/helper-validator-option" "^7.14.5"
-    "@babel/plugin-transform-typescript" "^7.15.0"
+    "@babel/helper-plugin-utils" "^7.18.6"
+    "@babel/helper-validator-option" "^7.18.6"
+    "@babel/plugin-transform-typescript" "^7.18.6"
 
-"@babel/runtime@^7.1.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.14.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
-  version "7.15.3"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.3.tgz#2e1c2880ca118e5b2f9988322bd8a7656a32502b"
-  integrity sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa"
+  integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==
   dependencies:
     regenerator-runtime "^0.13.4"
 
-"@babel/template@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.14.5.tgz#a9bc9d8b33354ff6e55a9c60d1109200a68974f4"
-  integrity sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==
-  dependencies:
-    "@babel/code-frame" "^7.14.5"
-    "@babel/parser" "^7.14.5"
-    "@babel/types" "^7.14.5"
-
-"@babel/traverse@^7.0.0-beta.54", "@babel/traverse@^7.13.0", "@babel/traverse@^7.14.5", "@babel/traverse@^7.15.0":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.0.tgz#4cca838fd1b2a03283c1f38e141f639d60b3fc98"
-  integrity sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==
-  dependencies:
-    "@babel/code-frame" "^7.14.5"
-    "@babel/generator" "^7.15.0"
-    "@babel/helper-function-name" "^7.14.5"
-    "@babel/helper-hoist-variables" "^7.14.5"
-    "@babel/helper-split-export-declaration" "^7.14.5"
-    "@babel/parser" "^7.15.0"
-    "@babel/types" "^7.15.0"
+"@babel/runtime@^7.17.2":
+  version "7.17.8"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2"
+  integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
+"@babel/runtime@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
+  integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
+"@babel/template@^7.16.7":
+  version "7.16.7"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155"
+  integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==
+  dependencies:
+    "@babel/code-frame" "^7.16.7"
+    "@babel/parser" "^7.16.7"
+    "@babel/types" "^7.16.7"
+
+"@babel/template@^7.18.6":
+  version "7.18.6"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
+  integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==
+  dependencies:
+    "@babel/code-frame" "^7.18.6"
+    "@babel/parser" "^7.18.6"
+    "@babel/types" "^7.18.6"
+
+"@babel/traverse@^7.0.0-beta.54", "@babel/traverse@^7.16.7":
+  version "7.16.8"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.8.tgz#bab2f2b09a5fe8a8d9cad22cbfe3ba1d126fef9c"
+  integrity sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==
+  dependencies:
+    "@babel/code-frame" "^7.16.7"
+    "@babel/generator" "^7.16.8"
+    "@babel/helper-environment-visitor" "^7.16.7"
+    "@babel/helper-function-name" "^7.16.7"
+    "@babel/helper-hoist-variables" "^7.16.7"
+    "@babel/helper-split-export-declaration" "^7.16.7"
+    "@babel/parser" "^7.16.8"
+    "@babel/types" "^7.16.8"
     debug "^4.1.0"
     globals "^11.1.0"
 
-"@babel/types@^7", "@babel/types@^7.0.0-beta.54", "@babel/types@^7.14.5", "@babel/types@^7.14.8", "@babel/types@^7.15.0", "@babel/types@^7.4.4":
-  version "7.15.0"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.0.tgz#61af11f2286c4e9c69ca8deb5f4375a73c72dcbd"
-  integrity sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==
+"@babel/traverse@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98"
+  integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==
+  dependencies:
+    "@babel/code-frame" "^7.18.6"
+    "@babel/generator" "^7.18.9"
+    "@babel/helper-environment-visitor" "^7.18.9"
+    "@babel/helper-function-name" "^7.18.9"
+    "@babel/helper-hoist-variables" "^7.18.6"
+    "@babel/helper-split-export-declaration" "^7.18.6"
+    "@babel/parser" "^7.18.9"
+    "@babel/types" "^7.18.9"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
+"@babel/types@^7", "@babel/types@^7.0.0-beta.54", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.4.4":
+  version "7.16.8"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1"
+  integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==
   dependencies:
-    "@babel/helper-validator-identifier" "^7.14.9"
+    "@babel/helper-validator-identifier" "^7.16.7"
+    to-fast-properties "^2.0.0"
+
+"@babel/types@^7.18.6", "@babel/types@^7.18.9":
+  version "7.18.9"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
+  integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.18.6"
     to-fast-properties "^2.0.0"
 
 "@discoveryjs/json-ext@^0.5.0":
-  version "0.5.3"
-  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz#90420f9f9c6d3987f176a19a7d8e764271a2f55d"
-  integrity sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==
+  version "0.5.6"
+  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz#d5e0706cf8c6acd8c6032f8d54070af261bbbb2f"
+  integrity sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==
 
-"@eslint/eslintrc@^0.4.3":
-  version "0.4.3"
-  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c"
-  integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==
+"@eslint/eslintrc@^1.3.0":
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f"
+  integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==
   dependencies:
     ajv "^6.12.4"
-    debug "^4.1.1"
-    espree "^7.3.0"
-    globals "^13.9.0"
-    ignore "^4.0.6"
+    debug "^4.3.2"
+    espree "^9.3.2"
+    globals "^13.15.0"
+    ignore "^5.2.0"
     import-fresh "^3.2.1"
-    js-yaml "^3.13.1"
-    minimatch "^3.0.4"
+    js-yaml "^4.1.0"
+    minimatch "^3.1.2"
     strip-json-comments "^3.1.1"
 
-"@humanwhocodes/config-array@^0.5.0":
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9"
-  integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==
+"@humanwhocodes/config-array@^0.9.2":
+  version "0.9.2"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.2.tgz#68be55c737023009dfc5fe245d51181bb6476914"
+  integrity sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==
   dependencies:
-    "@humanwhocodes/object-schema" "^1.2.0"
+    "@humanwhocodes/object-schema" "^1.2.1"
     debug "^4.1.1"
     minimatch "^3.0.4"
 
-"@humanwhocodes/object-schema@^1.2.0":
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz#87de7af9c231826fdd68ac7258f77c429e0e5fcf"
-  integrity sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==
+"@humanwhocodes/object-schema@^1.2.1":
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
+  integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
 
 "@iarna/cli@^1.2.0":
   version "1.2.0"
     update-notifier "^2.2.0"
     yargs "^8.0.2"
 
+"@jridgewell/gen-mapping@^0.3.0":
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9"
+  integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==
+  dependencies:
+    "@jridgewell/set-array" "^1.0.0"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/gen-mapping@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
+  integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
+  dependencies:
+    "@jridgewell/set-array" "^1.0.1"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/resolve-uri@^3.0.3":
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c"
+  integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==
+
+"@jridgewell/set-array@^1.0.0":
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea"
+  integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==
+
+"@jridgewell/set-array@^1.0.1":
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
+  integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
+
+"@jridgewell/source-map@^0.3.2":
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
+  integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
+  dependencies:
+    "@jridgewell/gen-mapping" "^0.3.0"
+    "@jridgewell/trace-mapping" "^0.3.9"
+
+"@jridgewell/sourcemap-codec@^1.4.10":
+  version "1.4.11"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec"
+  integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==
+
+"@jridgewell/trace-mapping@^0.3.0":
+  version "0.3.4"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3"
+  integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.0.3"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@jridgewell/trace-mapping@^0.3.9":
+  version "0.3.13"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea"
+  integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.0.3"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+
+"@leichtgewicht/ip-codec@^2.0.1":
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz#0300943770e04231041a51bd39f0439b5c7ab4f0"
+  integrity sha512-nkalE/f1RvRGChwBnEIoBfSEYOXnCRdleKuv6+lePbMDrMZXeDQnqak5XDOeBgrPPyPfAdcCu/B5z+v3VhplGg==
+
 "@nodelib/fs.scandir@2.1.5":
   version "2.1.5"
   resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
     "@nodelib/fs.scandir" "2.1.5"
     fastq "^1.6.0"
 
-"@popperjs/core@^2.8.3":
-  version "2.9.3"
-  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.3.tgz#8b68da1ebd7fc603999cf6ebee34a4899a14b88e"
-  integrity sha512-xDu17cEfh7Kid/d95kB6tZsLOmSWKCZKtprnhVepjsSaCij+lM3mItSJDuuHDMbCWTh8Ejmebwb+KONcCJ0eXQ==
+"@popperjs/core@^2.9.0":
+  version "2.11.2"
+  resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.2.tgz#830beaec4b4091a9e9398ac50f865ddea52186b9"
+  integrity sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA==
+
+"@sniptt/monads@^0.5.10":
+  version "0.5.10"
+  resolved "https://registry.yarnpkg.com/@sniptt/monads/-/monads-0.5.10.tgz#a80cd00738bbd682d36d36dd36bdc0bddc96eb76"
+  integrity sha512-+agDOv9DpDV+9e2zN/Vmdk+XaqGx5Sykl0fqhqgiJ90r18nsBkxe44DmZ2sA1HYK+MSsBeZBiAr6pq4w+5uhfw==
 
 "@types/autosize@^4.0.0":
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/@types/autosize/-/autosize-4.0.0.tgz#36a7659d99c7672957b2d1064c75f7c460efd074"
-  integrity sha512-FIEyxf173EjECl5xxib+pCLzmyxGJKyb971QJD8xftrEUdmb5U4K4Ym8H0V/TPT4ZEwtoQC1oC6o0enVvVelKQ==
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/@types/autosize/-/autosize-4.0.1.tgz#999a7c305b96766248044ebaac1a0299961f3b61"
+  integrity sha512-iPJT/FCaSO79G6j+9n6gmFc5nhxZ1gDrA2UAvb5FslJ6FJQZnDfbBU0qp5vpp0Cbjj7+gOyjuWZ7RrXvRuETaA==
 
 "@types/body-parser@*":
-  version "1.19.1"
-  resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.1.tgz#0c0174c42a7d017b818303d4b5d969cb0b75929c"
-  integrity sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==
+  version "1.19.2"
+  resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0"
+  integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==
   dependencies:
     "@types/connect" "*"
     "@types/node" "*"
 
+"@types/bonjour@^3.5.9":
+  version "3.5.10"
+  resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275"
+  integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==
+  dependencies:
+    "@types/node" "*"
+
+"@types/connect-history-api-fallback@^1.3.5":
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz#d1f7a8a09d0ed5a57aee5ae9c18ab9b803205dae"
+  integrity sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==
+  dependencies:
+    "@types/express-serve-static-core" "*"
+    "@types/node" "*"
+
 "@types/connect@*":
   version "3.4.35"
   resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1"
   dependencies:
     "@types/node" "*"
 
-"@types/eslint-scope@^3.7.0":
-  version "3.7.1"
-  resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.1.tgz#8dc390a7b4f9dd9f1284629efce982e41612116e"
-  integrity sha512-SCFeogqiptms4Fg29WpOTk5nHIzfpKCemSN63ksBQYKTcXoJEmJagV+DhVmbapZzY4/5YaOV1nZwrsU79fFm1g==
+"@types/eslint-scope@^3.7.3":
+  version "3.7.3"
+  resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224"
+  integrity sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==
   dependencies:
     "@types/eslint" "*"
     "@types/estree" "*"
 
 "@types/eslint@*":
-  version "7.28.0"
-  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.28.0.tgz#7e41f2481d301c68e14f483fe10b017753ce8d5a"
-  integrity sha512-07XlgzX0YJUn4iG1ocY4IX9DzKSmMGUs6ESKlxWhZRaa0fatIWaHWUVapcuGa8r5HFnTqzj+4OCjd5f7EZ/i/A==
+  version "8.2.2"
+  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.2.tgz#b64dbdb64b1957cfc8a698c68297fcf8983e94c7"
+  integrity sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==
   dependencies:
     "@types/estree" "*"
     "@types/json-schema" "*"
 
-"@types/estree@*", "@types/estree@^0.0.50":
+"@types/estree@*":
   version "0.0.50"
   resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83"
   integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==
 
-"@types/express-serve-static-core@^4.17.18":
-  version "4.17.24"
-  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz#ea41f93bf7e0d59cd5a76665068ed6aab6815c07"
-  integrity sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==
+"@types/estree@^0.0.51":
+  version "0.0.51"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40"
+  integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==
+
+"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18":
+  version "4.17.27"
+  resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz#7a776191e47295d2a05962ecbb3a4ce97e38b401"
+  integrity sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA==
   dependencies:
     "@types/node" "*"
     "@types/qs" "*"
     "@types/range-parser" "*"
 
-"@types/express@^4.17.13":
+"@types/express@*", "@types/express@^4.17.13":
   version "4.17.13"
   resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034"
   integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
     "@types/serve-static" "*"
 
 "@types/glob@^7.1.1":
-  version "7.1.4"
-  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672"
-  integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
+  integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
   dependencies:
     "@types/minimatch" "*"
     "@types/node" "*"
 
-"@types/http-proxy@^1.17.5":
-  version "1.17.7"
-  resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.7.tgz#30ea85cc2c868368352a37f0d0d3581e24834c6f"
-  integrity sha512-9hdj6iXH64tHSLTY+Vt2eYOGzSogC+JQ2H7bdPWkuh7KXP5qLllWx++t+K9Wk556c3dkDdPws/SpMRi0sdCT1w==
+"@types/http-proxy@^1.17.8":
+  version "1.17.8"
+  resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.8.tgz#968c66903e7e42b483608030ee85800f22d03f55"
+  integrity sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==
   dependencies:
     "@types/node" "*"
 
-"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8":
+"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
   version "7.0.9"
   resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d"
   integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==
   resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
   integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
 
-"@types/minimist@^1.2.0":
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c"
-  integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==
-
-"@types/node-fetch@^2.5.11":
-  version "2.5.12"
-  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.12.tgz#8a6f779b1d4e60b7a57fb6fd48d84fb545b9cc66"
-  integrity sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==
+"@types/node-fetch@^2.6.2":
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da"
+  integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==
   dependencies:
     "@types/node" "*"
     form-data "^3.0.0"
 
 "@types/node@*":
-  version "16.6.2"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.6.2.tgz#331b7b9f8621c638284787c5559423822fdffc50"
-  integrity sha512-LSw8TZt12ZudbpHc6EkIyDM3nHVWKYrAvGy6EAJfNfjusbwnThqjqxUKKRwuV3iWYeW/LYMzNgaq3MaLffQ2xA==
+  version "17.0.8"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b"
+  integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg==
 
-"@types/node@^16.7.1":
-  version "16.7.1"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.1.tgz#c6b9198178da504dfca1fd0be9b2e1002f1586f0"
-  integrity sha512-ncRdc45SoYJ2H4eWU9ReDfp3vtFqDYhjOsKlFFUDEn8V1Bgr2RjYal8YT5byfadWIRluhPFU6JiDOl0H6Sl87A==
-
-"@types/normalize-package-data@^2.4.0":
-  version "2.4.1"
-  resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301"
-  integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==
-
-"@types/parse-json@^4.0.0":
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
-  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+"@types/node@^18.6.2":
+  version "18.6.2"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.2.tgz#ffc5f0f099d27887c8d9067b54e55090fcd54126"
+  integrity sha512-KcfkBq9H4PI6Vpu5B/KoPeuVDAbmi+2mDBqGPGUgoL7yXQtcWGu2vJWmmRkneWK3Rh0nIAX192Aa87AqKHYChQ==
 
 "@types/qs@*":
   version "6.9.7"
   integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==
 
 "@types/serialize-javascript@^5.0.1":
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/@types/serialize-javascript/-/serialize-javascript-5.0.1.tgz#2c32e0626734a02a83b94cb924699c4bdcb6fd94"
-  integrity sha512-QqgTcm7IgIt/oWNFQMlpVv5Z3saYtxWK9yFrAUkk3jxvjbqIG835xNNoOYq12mXKQMuWGc+PgOXwXy92eax5BA==
+  version "5.0.2"
+  resolved "https://registry.yarnpkg.com/@types/serialize-javascript/-/serialize-javascript-5.0.2.tgz#c4b29f763e407def2502c9dfcc0b8c4c96ef0387"
+  integrity sha512-BRLlwZzRoZukGaBtcUxkLsZsQfWZpvog6MZk3PWQO9Q6pXmXFzjU5iGzZ+943evp6tkkbN98N1Z31KT0UG1yRw==
+
+"@types/serve-index@^1.9.1":
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278"
+  integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==
+  dependencies:
+    "@types/express" "*"
 
-"@types/serve-static@*":
+"@types/serve-static@*", "@types/serve-static@^1.13.10":
   version "1.13.10"
   resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.10.tgz#f5e0ce8797d2d7cc5ebeda48a52c96c4fa47a8d9"
   integrity sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==
     "@types/mime" "^1"
     "@types/node" "*"
 
-"@typescript-eslint/eslint-plugin@^4.28.3":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz#f54dc0a32b8f61c6024ab8755da05363b733838d"
-  integrity sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg==
+"@types/sockjs@^0.3.33":
+  version "0.3.33"
+  resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f"
+  integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==
   dependencies:
-    "@typescript-eslint/experimental-utils" "4.29.2"
-    "@typescript-eslint/scope-manager" "4.29.2"
-    debug "^4.3.1"
+    "@types/node" "*"
+
+"@types/ws@^8.5.1":
+  version "8.5.3"
+  resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.3.tgz#7d25a1ffbecd3c4f2d35068d0b283c037003274d"
+  integrity sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==
+  dependencies:
+    "@types/node" "*"
+
+"@typescript-eslint/eslint-plugin@^5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz#cae1967b1e569e6171bbc6bec2afa4e0c8efccfe"
+  integrity sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ==
+  dependencies:
+    "@typescript-eslint/scope-manager" "5.31.0"
+    "@typescript-eslint/type-utils" "5.31.0"
+    "@typescript-eslint/utils" "5.31.0"
+    debug "^4.3.4"
     functional-red-black-tree "^1.0.1"
-    regexpp "^3.1.0"
-    semver "^7.3.5"
+    ignore "^5.2.0"
+    regexpp "^3.2.0"
+    semver "^7.3.7"
     tsutils "^3.21.0"
 
-"@typescript-eslint/experimental-utils@4.29.2":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz#5f67fb5c5757ef2cb3be64817468ba35c9d4e3b7"
-  integrity sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A==
+"@typescript-eslint/parser@^5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.31.0.tgz#7f42d7dcc68a0a6d80a0f3d9a65063aee7bb8d2c"
+  integrity sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==
   dependencies:
-    "@types/json-schema" "^7.0.7"
-    "@typescript-eslint/scope-manager" "4.29.2"
-    "@typescript-eslint/types" "4.29.2"
-    "@typescript-eslint/typescript-estree" "4.29.2"
-    eslint-scope "^5.1.1"
-    eslint-utils "^3.0.0"
+    "@typescript-eslint/scope-manager" "5.31.0"
+    "@typescript-eslint/types" "5.31.0"
+    "@typescript-eslint/typescript-estree" "5.31.0"
+    debug "^4.3.4"
 
-"@typescript-eslint/parser@^4.28.3":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.2.tgz#1c7744f4c27aeb74610c955d3dce9250e95c370a"
-  integrity sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g==
-  dependencies:
-    "@typescript-eslint/scope-manager" "4.29.2"
-    "@typescript-eslint/types" "4.29.2"
-    "@typescript-eslint/typescript-estree" "4.29.2"
-    debug "^4.3.1"
-
-"@typescript-eslint/scope-manager@4.29.2":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz#442b0f029d981fa402942715b1718ac7fcd5aa1b"
-  integrity sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA==
-  dependencies:
-    "@typescript-eslint/types" "4.29.2"
-    "@typescript-eslint/visitor-keys" "4.29.2"
-
-"@typescript-eslint/types@4.29.2":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.2.tgz#fc0489c6b89773f99109fb0aa0aaddff21f52fcd"
-  integrity sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ==
-
-"@typescript-eslint/typescript-estree@4.29.2":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz#a0ea8b98b274adbb2577100ba545ddf8bf7dc219"
-  integrity sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg==
-  dependencies:
-    "@typescript-eslint/types" "4.29.2"
-    "@typescript-eslint/visitor-keys" "4.29.2"
-    debug "^4.3.1"
-    globby "^11.0.3"
-    is-glob "^4.0.1"
-    semver "^7.3.5"
+"@typescript-eslint/scope-manager@5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz#f47a794ba84d9b818ab7f8f44fff55a61016c606"
+  integrity sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==
+  dependencies:
+    "@typescript-eslint/types" "5.31.0"
+    "@typescript-eslint/visitor-keys" "5.31.0"
+
+"@typescript-eslint/type-utils@5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz#70a0b7201360b5adbddb0c36080495aa08f6f3d9"
+  integrity sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w==
+  dependencies:
+    "@typescript-eslint/utils" "5.31.0"
+    debug "^4.3.4"
     tsutils "^3.21.0"
 
-"@typescript-eslint/visitor-keys@4.29.2":
-  version "4.29.2"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz#d2da7341f3519486f50655159f4e5ecdcb2cd1df"
-  integrity sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag==
+"@typescript-eslint/types@5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.31.0.tgz#7aa389122b64b18e473c1672fb3b8310e5f07a9a"
+  integrity sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==
+
+"@typescript-eslint/typescript-estree@5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz#eb92970c9d6e3946690d50c346fb9b1d745ee882"
+  integrity sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==
+  dependencies:
+    "@typescript-eslint/types" "5.31.0"
+    "@typescript-eslint/visitor-keys" "5.31.0"
+    debug "^4.3.4"
+    globby "^11.1.0"
+    is-glob "^4.0.3"
+    semver "^7.3.7"
+    tsutils "^3.21.0"
+
+"@typescript-eslint/utils@5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.31.0.tgz#e146fa00dca948bfe547d665b2138a2dc1b79acd"
+  integrity sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg==
   dependencies:
-    "@typescript-eslint/types" "4.29.2"
-    eslint-visitor-keys "^2.0.0"
+    "@types/json-schema" "^7.0.9"
+    "@typescript-eslint/scope-manager" "5.31.0"
+    "@typescript-eslint/types" "5.31.0"
+    "@typescript-eslint/typescript-estree" "5.31.0"
+    eslint-scope "^5.1.1"
+    eslint-utils "^3.0.0"
+
+"@typescript-eslint/visitor-keys@5.31.0":
+  version "5.31.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz#b0eca264df01ce85dceb76aebff3784629258f54"
+  integrity sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==
+  dependencies:
+    "@typescript-eslint/types" "5.31.0"
+    eslint-visitor-keys "^3.3.0"
 
 "@webassemblyjs/ast@1.11.1":
   version "1.11.1"
     "@webassemblyjs/ast" "1.11.1"
     "@xtuc/long" "4.2.2"
 
-"@webpack-cli/configtest@^1.0.4":
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.0.4.tgz#f03ce6311c0883a83d04569e2c03c6238316d2aa"
-  integrity sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==
+"@webpack-cli/configtest@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5"
+  integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==
 
-"@webpack-cli/info@^1.3.0":
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.3.0.tgz#9d78a31101a960997a4acd41ffd9b9300627fe2b"
-  integrity sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==
+"@webpack-cli/info@^1.5.0":
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1"
+  integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==
   dependencies:
     envinfo "^7.7.3"
 
-"@webpack-cli/serve@^1.5.2":
-  version "1.5.2"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.5.2.tgz#ea584b637ff63c5a477f6f21604b5a205b72c9ec"
-  integrity sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==
+"@webpack-cli/serve@^1.7.0":
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1"
+  integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==
 
 "@xtuc/ieee754@^1.2.0":
   version "1.2.0"
@@ -1369,7 +1764,7 @@ abbrev@1, abbrev@~1.1.1:
   resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
   integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
 
-accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
+accepts@~1.3.4, accepts@~1.3.5:
   version "1.3.7"
   resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
   integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
@@ -1377,25 +1772,33 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
     mime-types "~2.1.24"
     negotiator "0.6.2"
 
+accepts@~1.3.8:
+  version "1.3.8"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+  integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+  dependencies:
+    mime-types "~2.1.34"
+    negotiator "0.6.3"
+
 acorn-import-assertions@^1.7.6:
-  version "1.7.6"
-  resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.7.6.tgz#580e3ffcae6770eebeec76c3b9723201e9d01f78"
-  integrity sha512-FlVvVFA1TX6l3lp8VjDnYYq7R1nyW6x3svAt4nDgrWQ9SBaSh9CnbwgSUTasgfNfOG5HlM1ehugCvM+hjo56LA==
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"
+  integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
 
-acorn-jsx@^5.3.1:
+acorn-jsx@^5.3.2:
   version "5.3.2"
   resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
   integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
 
-acorn@^7.4.0:
-  version "7.4.1"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
-  integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+acorn@^8.5.0:
+  version "8.7.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
+  integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
 
-acorn@^8.4.1:
-  version "8.4.1"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.4.1.tgz#56c36251fc7cabc7096adc18f05afe814321a28c"
-  integrity sha512-asabaBSkEKosYKMITunzX177CXxQ4Q8BSSzMTKD+FefUhipQC70gfW5SiUDhYQ3vk8G+81HqQk7Fv9OXwwn9KA==
+acorn@^8.7.1:
+  version "8.8.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
+  integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
 
 agent-base@4, agent-base@^4.1.0, agent-base@^4.3.0:
   version "4.3.0"
@@ -1426,11 +1829,25 @@ aggregate-error@^3.0.0:
     clean-stack "^2.0.0"
     indent-string "^4.0.0"
 
+ajv-formats@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+  integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
+  dependencies:
+    ajv "^8.0.0"
+
 ajv-keywords@^3.5.2:
   version "3.5.2"
   resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
   integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
 
+ajv-keywords@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16"
+  integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==
+  dependencies:
+    fast-deep-equal "^3.1.3"
+
 ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
   version "6.12.6"
   resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -1441,21 +1858,16 @@ ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5:
     json-schema-traverse "^0.4.1"
     uri-js "^4.2.2"
 
-ajv@^8.0.1:
-  version "8.6.2"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.6.2.tgz#2fb45e0e5fcbc0813326c1c3da535d1881bb0571"
-  integrity sha512-9807RlWAgT564wT+DjeyU5OFMPjmzxVobvDFmNAhY+5zD6A2ly3jDp6sgnfyDtlIQ+7H97oc/DGCzzfu9rjw9w==
+ajv@^8.0.0, ajv@^8.8.0:
+  version "8.8.2"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.8.2.tgz#01b4fef2007a28bf75f0b7fc009f62679de4abbb"
+  integrity sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw==
   dependencies:
     fast-deep-equal "^3.1.1"
     json-schema-traverse "^1.0.0"
     require-from-string "^2.0.2"
     uri-js "^4.2.2"
 
-amdefine@>=0.0.4:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5"
-  integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
-
 ansi-align@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
@@ -1463,11 +1875,6 @@ ansi-align@^2.0.0:
   dependencies:
     string-width "^2.0.0"
 
-ansi-colors@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
-  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
-
 ansi-escapes@^4.3.0:
   version "4.3.2"
   resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
@@ -1475,10 +1882,10 @@ ansi-escapes@^4.3.0:
   dependencies:
     type-fest "^0.21.3"
 
-ansi-html@^0.0.7:
-  version "0.0.7"
-  resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
-  integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4=
+ansi-html-community@^0.0.8:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41"
+  integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==
 
 ansi-regex@^2.0.0:
   version "2.1.1"
@@ -1495,20 +1902,15 @@ ansi-regex@^4.1.0:
   resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
   integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
 
-ansi-regex@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
-  integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
-
-ansi-regex@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.0.tgz#ecc7f5933cbe5ac7b33e209a5ff409ab1669c6b2"
-  integrity sha512-tAaOSrWCHF+1Ear1Z4wnJCXA9GGox4K6Ic85a5qalES2aeEwQGr7UC93mwef49536PkCYjzkp0zIxfFvexJ6zQ==
+ansi-regex@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+  integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
 
-ansi-styles@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
-  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+ansi-regex@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
+  integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
 
 ansi-styles@^3.2.0, ansi-styles@^3.2.1:
   version "3.2.1"
@@ -1524,6 +1926,11 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
   dependencies:
     color-convert "^2.0.1"
 
+ansi-styles@^6.0.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3"
+  integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==
+
 ansicolors@~0.3.2:
   version "0.3.2"
   resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979"
@@ -1558,9 +1965,9 @@ archy@~1.0.0:
   integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=
 
 are-we-there-yet@~1.1.2:
-  version "1.1.5"
-  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
-  integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146"
+  integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==
   dependencies:
     delegates "^1.0.0"
     readable-stream "^2.0.6"
@@ -1582,7 +1989,7 @@ array-flatten@1.1.1:
   resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
   integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
 
-array-flatten@^2.1.0:
+array-flatten@^2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
   integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
@@ -1604,20 +2011,15 @@ array-uniq@^1.0.1:
   resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
   integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
 
-arrify@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
-  integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=
-
 asap@^2.0.0:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
   integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
 
 asn1@~0.2.3:
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
-  integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+  version "0.2.6"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
+  integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==
   dependencies:
     safer-buffer "~2.1.0"
 
@@ -1631,18 +2033,6 @@ astral-regex@^2.0.0:
   resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
   integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
 
-async-foreach@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
-  integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
-
-async@^2.6.2:
-  version "2.6.3"
-  resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
-  integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
-  dependencies:
-    lodash "^4.17.14"
-
 asynckit@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -1663,13 +2053,13 @@ aws4@^1.8.0:
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
   integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
 
-babel-loader@^8.2.2:
-  version "8.2.2"
-  resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81"
-  integrity sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==
+babel-loader@^8.2.5:
+  version "8.2.5"
+  resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.5.tgz#d45f585e654d5a5d90f5350a779d7647c5ed512e"
+  integrity sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==
   dependencies:
     find-cache-dir "^3.3.1"
-    loader-utils "^1.4.0"
+    loader-utils "^2.0.0"
     make-dir "^3.1.0"
     schema-utils "^2.6.5"
 
@@ -1680,37 +2070,37 @@ babel-plugin-dynamic-import-node@^2.3.3:
   dependencies:
     object.assign "^4.1.0"
 
-babel-plugin-inferno@^6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/babel-plugin-inferno/-/babel-plugin-inferno-6.3.0.tgz#4eb227149791f84b69fb5a728d159778dde08870"
-  integrity sha512-OtGA0KvsfiM1GTTNdrBynkNmOXIv+WiFFZa809PMqWCUwNmdaCWLRuAKbVFjsf0axXg5Uk/yIZSM9kmqEnKkkQ==
+babel-plugin-inferno@^6.5.0:
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-inferno/-/babel-plugin-inferno-6.5.0.tgz#38e4c2253e86bedbe633ac8f7232c1e1d7bf1875"
+  integrity sha512-JD/FvSGvg6B0SgQD0APtA2VOYz4lEg4ytuH0MsAgm+dgRbWICXiZe9cM5HNAsJIwjQpT2sQiwM/7/WaaRNeNPQ==
   dependencies:
     "@babel/plugin-syntax-jsx" "^7"
     "@babel/types" "^7"
 
-babel-plugin-polyfill-corejs2@^0.2.2:
-  version "0.2.2"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327"
-  integrity sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==
+babel-plugin-polyfill-corejs2@^0.3.1:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz#e4c31d4c89b56f3cf85b92558954c66b54bd972d"
+  integrity sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==
   dependencies:
-    "@babel/compat-data" "^7.13.11"
-    "@babel/helper-define-polyfill-provider" "^0.2.2"
+    "@babel/compat-data" "^7.17.7"
+    "@babel/helper-define-polyfill-provider" "^0.3.2"
     semver "^6.1.1"
 
-babel-plugin-polyfill-corejs3@^0.2.2:
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.4.tgz#68cb81316b0e8d9d721a92e0009ec6ecd4cd2ca9"
-  integrity sha512-z3HnJE5TY/j4EFEa/qpQMSbcUJZ5JQi+3UFjXzn6pQCmIKc5Ug5j98SuYyH+m4xQnvKlMDIW4plLfgyVnd0IcQ==
+babel-plugin-polyfill-corejs3@^0.5.2:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz#d7e09c9a899079d71a8b670c6181af56ec19c5c7"
+  integrity sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.2.2"
-    core-js-compat "^3.14.0"
+    "@babel/helper-define-polyfill-provider" "^0.3.2"
+    core-js-compat "^3.21.0"
 
-babel-plugin-polyfill-regenerator@^0.2.2:
-  version "0.2.2"
-  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz#b310c8d642acada348c1fa3b3e6ce0e851bee077"
-  integrity sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==
+babel-plugin-polyfill-regenerator@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990"
+  integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==
   dependencies:
-    "@babel/helper-define-polyfill-provider" "^0.2.2"
+    "@babel/helper-define-polyfill-provider" "^0.3.1"
 
 balanced-match@^1.0.0:
   version "1.0.2"
@@ -1768,43 +2158,43 @@ bluebird@~3.5.1:
   resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
   integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
 
-body-parser@1.19.0:
-  version "1.19.0"
-  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
-  integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+body-parser@1.20.0:
+  version "1.20.0"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5"
+  integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==
   dependencies:
-    bytes "3.1.0"
+    bytes "3.1.2"
     content-type "~1.0.4"
     debug "2.6.9"
-    depd "~1.1.2"
-    http-errors "1.7.2"
+    depd "2.0.0"
+    destroy "1.2.0"
+    http-errors "2.0.0"
     iconv-lite "0.4.24"
-    on-finished "~2.3.0"
-    qs "6.7.0"
-    raw-body "2.4.0"
-    type-is "~1.6.17"
+    on-finished "2.4.1"
+    qs "6.10.3"
+    raw-body "2.5.1"
+    type-is "~1.6.18"
+    unpipe "1.0.0"
 
-bonjour@^3.5.0:
-  version "3.5.0"
-  resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5"
-  integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU=
+bonjour-service@^1.0.11:
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.0.12.tgz#28fbd4683f5f2e36feedb833e24ba661cac960c3"
+  integrity sha512-pMmguXYCu63Ug37DluMKEHdxc+aaIf/ay4YbF8Gxtba+9d3u+rmEWy61VK3Z3hp8Rskok3BunHYnG0dUHAsblw==
   dependencies:
-    array-flatten "^2.1.0"
-    deep-equal "^1.0.1"
+    array-flatten "^2.1.2"
     dns-equal "^1.0.0"
-    dns-txt "^2.0.2"
-    multicast-dns "^6.0.1"
-    multicast-dns-service-types "^1.1.0"
+    fast-deep-equal "^3.1.3"
+    multicast-dns "^7.2.4"
 
-bootstrap@^5.0.2:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.1.0.tgz#543ef8f44f4b9af67b0230f19508542fec38ef55"
-  integrity sha512-bs74WNI9BgBo3cEovmdMHikSKoXnDgA6VQjJ7TyTotU6L7d41ZyCEEelPwkYEzsG/Zjv3ie9IE3EMAje0W9Xew==
+bootstrap@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-5.2.0.tgz#838727fb60f1630db370fe57c63cbcf2962bb3d3"
+  integrity sha512-qlnS9GL6YZE6Wnef46GxGv1UpGGzAwO0aPL1yOjzDIJpeApeMvqV24iL+pjr2kU4dduoBA9fINKWKgMToobx9A==
 
-bootswatch@^5.0.2:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/bootswatch/-/bootswatch-5.1.0.tgz#a9c521226aef55bba96b2854ef6fe39737b24f1a"
-  integrity sha512-HwQjahQSq0u+ydqY0fFyl/GsJIHhBvzjBA8D2XvMvIrHdqYfL1LdD5bnnaEDoJugMCYGud9PQSgq/XkuyFFPMg==
+bootswatch@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/bootswatch/-/bootswatch-5.2.0.tgz#c02a0d84e0382552f8a7b9bdd055f36b758ffed9"
+  integrity sha512-v9krdPdybb5hUwVwlv3f7/FhOa5cXbCb5U5CI4gdnalcxR3ekclXE6kPZWL5O8V8qwNI9BB73apASO1MLmRpIA==
 
 boxen@^1.2.1:
   version "1.3.0"
@@ -1827,34 +2217,39 @@ brace-expansion@^1.1.7:
     balanced-match "^1.0.0"
     concat-map "0.0.1"
 
-braces@^3.0.1, braces@~3.0.2:
+braces@^3.0.1, braces@^3.0.2, braces@~3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
   integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
   dependencies:
     fill-range "^7.0.1"
 
-browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.16.7:
-  version "4.16.8"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.8.tgz#cb868b0b554f137ba6e33de0ecff2eda403c4fb0"
-  integrity sha512-sc2m9ohR/49sWEbPj14ZSSZqp+kbi16aLao42Hmn3Z8FpjuMaq2xCA2l4zl9ITfyzvnvyE0hcg62YkIGKxgaNQ==
+browserslist@^4.14.5, browserslist@^4.17.5:
+  version "4.19.1"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3"
+  integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==
   dependencies:
-    caniuse-lite "^1.0.30001251"
-    colorette "^1.3.0"
-    electron-to-chromium "^1.3.811"
+    caniuse-lite "^1.0.30001286"
+    electron-to-chromium "^1.4.17"
     escalade "^3.1.1"
-    node-releases "^1.1.75"
+    node-releases "^2.0.1"
+    picocolors "^1.0.0"
+
+browserslist@^4.20.2, browserslist@^4.21.2:
+  version "4.21.3"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
+  integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
+  dependencies:
+    caniuse-lite "^1.0.30001370"
+    electron-to-chromium "^1.4.202"
+    node-releases "^2.0.6"
+    update-browserslist-db "^1.0.5"
 
 buffer-from@^1.0.0:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
   integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
 
-buffer-indexof@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
-  integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==
-
 builtin-modules@^1.0.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@@ -1885,10 +2280,10 @@ bytes@3.0.0:
   resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
   integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
 
-bytes@3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
-  integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+bytes@3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+  integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
 
 cacache@^10.0.0, cacache@^10.0.4:
   version "10.0.4"
@@ -1966,29 +2361,25 @@ callsites@^3.0.0:
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
   integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
 
-camelcase-keys@^6.2.2:
-  version "6.2.2"
-  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0"
-  integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==
-  dependencies:
-    camelcase "^5.3.1"
-    map-obj "^4.0.0"
-    quick-lru "^4.0.1"
-
 camelcase@^4.0.0, camelcase@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
   integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
 
-camelcase@^5.0.0, camelcase@^5.3.1:
+camelcase@^5.0.0:
   version "5.3.1"
   resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
   integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
 
-caniuse-lite@^1.0.30001251:
-  version "1.0.30001251"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz#6853a606ec50893115db660f82c094d18f096d85"
-  integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==
+caniuse-lite@^1.0.30001286:
+  version "1.0.30001298"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001298.tgz#0e690039f62e91c3ea581673d716890512e7ec52"
+  integrity sha512-AcKqikjMLlvghZL/vfTHorlQsLDhGRalYf1+GmWCf5SCMziSGjRYQW/JEksj14NaYHIR6KIhrFAy0HV5C25UzQ==
+
+caniuse-lite@^1.0.30001370:
+  version "1.0.30001373"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz#2dc3bc3bfcb5d5a929bec11300883040d7b4b4be"
+  integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==
 
 capture-stack-trace@^1.0.0:
   version "1.0.1"
@@ -2000,17 +2391,6 @@ caseless@~0.12.0:
   resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
   integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
 
-chalk@^1.1.1:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
-  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
-  dependencies:
-    ansi-styles "^2.2.1"
-    escape-string-regexp "^1.0.2"
-    has-ansi "^2.0.0"
-    strip-ansi "^3.0.0"
-    supports-color "^2.0.0"
-
 chalk@^2.0.0, chalk@^2.0.1:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -2020,7 +2400,7 @@ chalk@^2.0.0, chalk@^2.0.1:
     escape-string-regexp "^1.0.5"
     supports-color "^5.3.0"
 
-chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1:
+chalk@^4.0.0:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
   integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
@@ -2028,16 +2408,21 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1:
     ansi-styles "^4.1.0"
     supports-color "^7.1.0"
 
-choices.js@^9.0.1:
-  version "9.0.1"
-  resolved "https://registry.yarnpkg.com/choices.js/-/choices.js-9.0.1.tgz#745fb29af8670428fdc0bf1cc9dfaa404e9d0510"
-  integrity sha512-JgpeDY0Tmg7tqY6jaW/druSklJSt7W68tXFJIw0GSGWmO37SDAL8o60eICNGbzIODjj02VNNtf5h6TgoHDtCsA==
+check-password-strength@^2.0.7:
+  version "2.0.7"
+  resolved "https://registry.yarnpkg.com/check-password-strength/-/check-password-strength-2.0.7.tgz#d8fd6c1a274267c7ddd9cd15c71a3cfb6ad35baa"
+  integrity sha512-VyklBkB6dOKnCIh63zdVr7QKVMN9/npwUqNAXxWrz8HabVZH/n/d+lyNm1O/vbXFJlT/Hytb5ouYKYGkoeZirQ==
+
+choices.js@^10.1.0:
+  version "10.1.0"
+  resolved "https://registry.yarnpkg.com/choices.js/-/choices.js-10.1.0.tgz#034a40b7aa82e2a38f19ff8fae5bbfa6047862f4"
+  integrity sha512-NtrFt7c7ZQEGmkWsAV+EHynJhADWoZ82JEfg1+vQ9MMKJD4Ax2rzYPxXe+Q64i0HgUgWG/XTN3gN2pB8UFFFlA==
   dependencies:
-    deepmerge "^4.2.0"
-    fuse.js "^3.4.5"
-    redux "^4.0.4"
+    deepmerge "^4.2.2"
+    fuse.js "^6.5.3"
+    redux "^4.1.2"
 
-chokidar@^3.5.1:
+"chokidar@>=3.0.0 <4.0.0":
   version "3.5.2"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
   integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
@@ -2052,16 +2437,26 @@ chokidar@^3.5.1:
   optionalDependencies:
     fsevents "~2.3.2"
 
+chokidar@^3.5.3:
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+  dependencies:
+    anymatch "~3.1.2"
+    braces "~3.0.2"
+    glob-parent "~5.1.2"
+    is-binary-path "~2.1.0"
+    is-glob "~4.0.1"
+    normalize-path "~3.0.0"
+    readdirp "~3.6.0"
+  optionalDependencies:
+    fsevents "~2.3.2"
+
 chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2, chownr@^1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
   integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
 
-chownr@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
-  integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
-
 chownr@~1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181"
@@ -2082,15 +2477,25 @@ cidr-regex@1.0.6:
   resolved "https://registry.yarnpkg.com/cidr-regex/-/cidr-regex-1.0.6.tgz#74abfd619df370b9d54ab14475568e97dd64c0c1"
   integrity sha1-dKv9YZ3zcLnVSrFEdVaOl91kwME=
 
+class-transformer@^0.5.1:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336"
+  integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==
+
+classnames@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
+  integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
+
 clean-stack@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
   integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
 
-clean-webpack-plugin@^4.0.0-alpha.0:
-  version "4.0.0-alpha.0"
-  resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0-alpha.0.tgz#2aef48dfe7565360d128f5caa0904097d969d053"
-  integrity sha512-+X6mASBbGSVyw8L9/1rhQ+vS4uaQMopf194kX7Aes8qfezgCFL+qv5W0nwP3a0Tud5kUckARk8tFcoyOSKEjhg==
+clean-webpack-plugin@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz#72947d4403d452f38ed61a9ff0ada8122aacd729"
+  integrity sha512-WuWE1nyTNAyW5T7oNyys2EN0cfP2fdRxhxnIQWiAp0bMabPdHhoGxM8A6YL2GhqwgrPnnaemVE7nv5XJ2Fhh2w==
   dependencies:
     del "^4.1.1"
 
@@ -2142,6 +2547,14 @@ cli-truncate@^2.1.0:
     slice-ansi "^3.0.0"
     string-width "^4.2.0"
 
+cli-truncate@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389"
+  integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==
+  dependencies:
+    slice-ansi "^5.0.0"
+    string-width "^5.0.0"
+
 cliui@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d"
@@ -2219,10 +2632,15 @@ color-name@~1.1.4:
   resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
-colorette@^1.2.1, colorette@^1.2.2, colorette@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.3.0.tgz#ff45d2f0edb244069d3b772adeb04fed38d0a0af"
-  integrity sha512-ecORCqbSFP7Wm8Y6lyqMJjexBQqXSF7SSeaTyGGphogUjBlFP9m9o08wy86HL2uB7fMTxtOUzLMk7ogKcxMg1w==
+colorette@^2.0.10, colorette@^2.0.14, colorette@^2.0.16:
+  version "2.0.16"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da"
+  integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==
+
+colorette@^2.0.17:
+  version "2.0.19"
+  resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
+  integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
 
 colors@^1.1.2:
   version "1.4.0"
@@ -2249,11 +2667,16 @@ commander@^2.20.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
   integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
 
-commander@^7.0.0, commander@^7.2.0:
+commander@^7.0.0:
   version "7.2.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
   integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
 
+commander@^9.3.0:
+  version "9.4.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c"
+  integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==
+
 commondir@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
@@ -2314,22 +2737,22 @@ configstore@^3.0.0:
     write-file-atomic "^2.0.0"
     xdg-basedir "^3.0.0"
 
-connect-history-api-fallback@^1.6.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
-  integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
+connect-history-api-fallback@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
+  integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
 
 console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
   integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
 
-content-disposition@0.5.3:
-  version "0.5.3"
-  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
-  integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+content-disposition@0.5.4:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+  integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
   dependencies:
-    safe-buffer "5.1.2"
+    safe-buffer "5.2.1"
 
 content-type@~1.0.4:
   version "1.0.4"
@@ -2348,10 +2771,10 @@ cookie-signature@1.0.6:
   resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
   integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
 
-cookie@0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
-  integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+cookie@0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+  integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
 
 cookie@^0.1.2:
   version "0.1.5"
@@ -2370,32 +2793,36 @@ copy-concurrently@^1.0.0:
     rimraf "^2.5.4"
     run-queue "^1.0.0"
 
-copy-webpack-plugin@^9.0.1:
-  version "9.0.1"
-  resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-9.0.1.tgz#b71d21991599f61a4ee00ba79087b8ba279bbb59"
-  integrity sha512-14gHKKdYIxF84jCEgPgYXCPpldbwpxxLbCmA7LReY7gvbaT555DgeBWBgBZM116tv/fO6RRJrsivBqRyRlukhw==
+copy-webpack-plugin@^11.0.0:
+  version "11.0.0"
+  resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a"
+  integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==
   dependencies:
-    fast-glob "^3.2.5"
-    glob-parent "^6.0.0"
-    globby "^11.0.3"
+    fast-glob "^3.2.11"
+    glob-parent "^6.0.1"
+    globby "^13.1.1"
     normalize-path "^3.0.0"
-    p-limit "^3.1.0"
-    schema-utils "^3.0.0"
+    schema-utils "^4.0.0"
     serialize-javascript "^6.0.0"
 
-core-js-compat@^3.14.0, core-js-compat@^3.16.0:
-  version "3.16.2"
-  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.16.2.tgz#442ef1d933ca6fc80859bd5a1db7a3ba716aaf56"
-  integrity sha512-4lUshXtBXsdmp8cDWh6KKiHUg40AjiuPD3bOWkNVsr1xkAhpUqCjaZ8lB1bKx9Gb5fXcbRbFJ4f4qpRIRTuJqQ==
+core-js-compat@^3.21.0, core-js-compat@^3.22.1:
+  version "3.24.0"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.24.0.tgz#885958fac38bf3f4464a90f2663b4620f6aee6e3"
+  integrity sha512-F+2E63X3ff/nj8uIrf8Rf24UDGIz7p838+xjEp+Bx3y8OWXj+VTPPZNCtdqovPaS9o7Tka5mCH01Zn5vOd6UQg==
   dependencies:
-    browserslist "^4.16.7"
+    browserslist "^4.21.2"
     semver "7.0.0"
 
-core-util-is@1.0.2, core-util-is@~1.0.0:
+core-util-is@1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
   integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
 
+core-util-is@~1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+  integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
 cosmiconfig@^5.0.5:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
@@ -2406,17 +2833,6 @@ cosmiconfig@^5.0.5:
     js-yaml "^3.13.1"
     parse-json "^4.0.0"
 
-cosmiconfig@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3"
-  integrity sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==
-  dependencies:
-    "@types/parse-json" "^4.0.0"
-    import-fresh "^3.2.1"
-    parse-json "^5.0.0"
-    path-type "^4.0.0"
-    yaml "^1.10.0"
-
 create-error-class@^3.0.0:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
@@ -2447,18 +2863,18 @@ crypto-random-string@^1.0.0:
   resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
   integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
 
-css-loader@^6.0.0:
-  version "6.2.0"
-  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.2.0.tgz#9663d9443841de957a3cb9bcea2eda65b3377071"
-  integrity sha512-/rvHfYRjIpymZblf49w8jYcRo2y9gj6rV8UroHGmBxKrIyGLokpycyKzp9OkitvqT29ZSpzJ0Ic7SpnJX3sC8g==
+css-loader@^6.7.1:
+  version "6.7.1"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.7.1.tgz#e98106f154f6e1baf3fc3bc455cb9981c1d5fd2e"
+  integrity sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==
   dependencies:
     icss-utils "^5.1.0"
-    postcss "^8.2.15"
+    postcss "^8.4.7"
     postcss-modules-extract-imports "^3.0.0"
     postcss-modules-local-by-default "^4.0.0"
     postcss-modules-scope "^3.0.0"
     postcss-modules-values "^4.0.0"
-    postcss-value-parser "^4.1.0"
+    postcss-value-parser "^4.2.0"
     semver "^7.3.5"
 
 cssesc@^3.0.0:
@@ -2492,17 +2908,24 @@ debug@3.1.0:
   dependencies:
     ms "2.0.0"
 
-debug@^3.1.0, debug@^3.1.1:
+debug@^3.1.0:
   version "3.2.7"
   resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
   integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
   dependencies:
     ms "^2.1.1"
 
-debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
-  version "4.3.2"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
-  integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
+debug@^4.1.0, debug@^4.1.1, debug@^4.3.2:
+  version "4.3.3"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
+  integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
+  dependencies:
+    ms "2.1.2"
+
+debug@^4.3.4:
+  version "4.3.4"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
   dependencies:
     ms "2.1.2"
 
@@ -2511,15 +2934,7 @@ debuglog@^1.0.1:
   resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
   integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
 
-decamelize-keys@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
-  integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
-  dependencies:
-    decamelize "^1.1.0"
-    map-obj "^1.0.0"
-
-decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0:
+decamelize@^1.1.1, decamelize@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
   integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
@@ -2547,16 +2962,16 @@ deep-extend@^0.6.0:
   integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
 
 deep-is@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
-  integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+  integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
 
-deepmerge@^4.2.0:
+deepmerge@^4.2.2:
   version "4.2.2"
   resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
   integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
 
-default-gateway@^6.0.0:
+default-gateway@^6.0.3:
   version "6.0.3"
   resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
   integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==
@@ -2595,20 +3010,6 @@ del@^4.1.1:
     pify "^4.0.1"
     rimraf "^2.6.3"
 
-del@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952"
-  integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==
-  dependencies:
-    globby "^11.0.1"
-    graceful-fs "^4.2.4"
-    is-glob "^4.0.1"
-    is-path-cwd "^2.2.0"
-    is-path-inside "^3.0.2"
-    p-map "^4.0.0"
-    rimraf "^3.0.2"
-    slash "^3.0.0"
-
 delayed-stream@~1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@@ -2619,15 +3020,20 @@ delegates@^1.0.0:
   resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
   integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
 
+depd@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+  integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
 depd@~1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
   integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
 
-destroy@~1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
-  integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+destroy@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+  integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
 
 detect-indent@^6.0.0:
   version "6.1.0"
@@ -2674,20 +3080,12 @@ dns-equal@^1.0.0:
   resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
   integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0=
 
-dns-packet@^1.3.1:
-  version "1.3.4"
-  resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.4.tgz#e3455065824a2507ba886c55a89963bb107dec6f"
-  integrity sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==
-  dependencies:
-    ip "^1.1.0"
-    safe-buffer "^5.0.1"
-
-dns-txt@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6"
-  integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=
+dns-packet@^5.2.2:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.3.1.tgz#eb94413789daec0f0ebe2fcc230bdc9d7c91b43d"
+  integrity sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==
   dependencies:
-    buffer-indexof "^1.0.0"
+    "@leichtgewicht/ip-codec" "^2.0.1"
 
 doctrine@^3.0.0:
   version "3.0.0"
@@ -2723,6 +3121,11 @@ duplexify@^3.4.2, duplexify@^3.6.0:
     readable-stream "^2.0.0"
     stream-shift "^1.0.0"
 
+eastasianwidth@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+  integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
 ecc-jsbn@~0.1.1:
   version "0.1.2"
   resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
@@ -2741,10 +3144,15 @@ ee-first@1.1.1:
   resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
   integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
 
-electron-to-chromium@^1.3.811:
-  version "1.3.813"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.813.tgz#751a007d71c00faed8b5e9edaf3634c14b9c5a1f"
-  integrity sha512-YcSRImHt6JZZ2sSuQ4Bzajtk98igQ0iKkksqlzZLzbh4p0OIyJRSvUbsgqfcR8txdfsoYCc4ym306t4p2kP/aw==
+electron-to-chromium@^1.4.17:
+  version "1.4.41"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.41.tgz#0b2e126796e7fafb9fd71e29304468b9d0af5d65"
+  integrity sha512-VQEXEJc+8rJIva85H8EPtB5Ux9g8TzkNGBanqphM9ZWMZ34elueKJ+5g+BPhz3Lk8gkujfQRcIZ+fpA0btUIuw==
+
+electron-to-chromium@^1.4.202:
+  version "1.4.206"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz#580ff85b54d7ec0c05f20b1e37ea0becdd7b0ee4"
+  integrity sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==
 
 emoji-regex@^7.0.1:
   version "7.0.3"
@@ -2756,10 +3164,15 @@ emoji-regex@^8.0.0:
   resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
   integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
 
-emoji-short-name@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/emoji-short-name/-/emoji-short-name-1.0.0.tgz#82e6f543b6c68984d69bdc80eac735104fdd4af8"
-  integrity sha512-+tiniHvgRR7XMI1jAaGveumWg5LALE/nWkFD6CcOn6M5IDM9w4PkMs8UwzLTMoZtDLdTdQmzxGvLOxHVIjPzjg==
+emoji-regex@^9.2.2:
+  version "9.2.2"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+  integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+emoji-short-name@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/emoji-short-name/-/emoji-short-name-2.0.0.tgz#1f4fff6f93757cb59aae14f9f1646c25c0cadc8f"
+  integrity sha512-5M8cb34AgSAKd1kD2lAK4keISXdm6sG83q/6XBVGNgzIAB9ykPmxrcIhyYi1WwzhaF0vg5MVIIqOQ4D9FqXX/A==
 
 emojis-list@^3.0.0:
   version "3.0.0"
@@ -2785,30 +3198,23 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
   dependencies:
     once "^1.4.0"
 
-enhanced-resolve@^5.8.0:
-  version "5.8.2"
-  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b"
-  integrity sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==
+enhanced-resolve@^5.10.0:
+  version "5.10.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6"
+  integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==
   dependencies:
     graceful-fs "^4.2.4"
     tapable "^2.2.0"
 
-enquirer@^2.3.5, enquirer@^2.3.6:
-  version "2.3.6"
-  resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
-  integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
-  dependencies:
-    ansi-colors "^4.1.1"
-
-entities@~2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
-  integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
+entities@~1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
+  integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
 
-env-paths@^2.2.0:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2"
-  integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==
+entities@~3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-3.0.1.tgz#2b887ca62585e96db3903482d336c1006c3001d4"
+  integrity sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==
 
 envinfo@^7.7.3:
   version "7.8.1"
@@ -2834,22 +3240,25 @@ error-ex@^1.2.0, error-ex@^1.3.1:
   dependencies:
     is-arrayish "^0.2.1"
 
-es-abstract@^1.18.0-next.2:
-  version "1.18.5"
-  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19"
-  integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==
+es-abstract@^1.19.1:
+  version "1.19.1"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3"
+  integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==
   dependencies:
     call-bind "^1.0.2"
     es-to-primitive "^1.2.1"
     function-bind "^1.1.1"
     get-intrinsic "^1.1.1"
+    get-symbol-description "^1.0.0"
     has "^1.0.3"
     has-symbols "^1.0.2"
     internal-slot "^1.0.3"
-    is-callable "^1.2.3"
+    is-callable "^1.2.4"
     is-negative-zero "^2.0.1"
-    is-regex "^1.1.3"
-    is-string "^1.0.6"
+    is-regex "^1.1.4"
+    is-shared-array-buffer "^1.0.1"
+    is-string "^1.0.7"
+    is-weakref "^1.0.1"
     object-inspect "^1.11.0"
     object-keys "^1.1.1"
     object.assign "^4.1.2"
@@ -2857,10 +3266,10 @@ es-abstract@^1.18.0-next.2:
     string.prototype.trimstart "^1.0.4"
     unbox-primitive "^1.0.1"
 
-es-module-lexer@^0.7.1:
-  version "0.7.1"
-  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.7.1.tgz#c2c8e0f46f2df06274cdaf0dd3f3b33e0a0b267d"
-  integrity sha512-MgtWFl5No+4S3TmhDmCz2ObFGm6lEpTnzbQi+Dd+pw4mlTIZTmM2iAs5gRlmx5zS9luzobCSBSI90JM/1/JgOw==
+es-module-lexer@^0.9.0:
+  version "0.9.3"
+  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.9.3.tgz#6f13db00cc38417137daf74366f535c8eb438f19"
+  integrity sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==
 
 es-to-primitive@^1.2.1:
   version "1.2.1"
@@ -2893,7 +3302,7 @@ escape-html@~1.0.3:
   resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
   integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
 
-escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+escape-string-regexp@^1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
@@ -2903,10 +3312,10 @@ escape-string-regexp@^4.0.0:
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
   integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
 
-eslint-plugin-prettier@^3.4.1:
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz#e9ddb200efb6f3d05ffe83b1665a716af4a387e5"
-  integrity sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==
+eslint-plugin-prettier@^4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
+  integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
   dependencies:
     prettier-linter-helpers "^1.0.0"
 
@@ -2918,12 +3327,13 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1:
     esrecurse "^4.3.0"
     estraverse "^4.1.1"
 
-eslint-utils@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
-  integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
+eslint-scope@^7.1.1:
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642"
+  integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==
   dependencies:
-    eslint-visitor-keys "^1.1.0"
+    esrecurse "^4.3.0"
+    estraverse "^5.2.0"
 
 eslint-utils@^3.0.0:
   version "3.0.0"
@@ -2932,70 +3342,65 @@ eslint-utils@^3.0.0:
   dependencies:
     eslint-visitor-keys "^2.0.0"
 
-eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
-  integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
-
 eslint-visitor-keys@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
   integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
 
-eslint@^7.30.0:
-  version "7.32.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d"
-  integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==
+eslint-visitor-keys@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826"
+  integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==
+
+eslint@^8.20.0:
+  version "8.20.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.20.0.tgz#048ac56aa18529967da8354a478be4ec0a2bc81b"
+  integrity sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==
   dependencies:
-    "@babel/code-frame" "7.12.11"
-    "@eslint/eslintrc" "^0.4.3"
-    "@humanwhocodes/config-array" "^0.5.0"
+    "@eslint/eslintrc" "^1.3.0"
+    "@humanwhocodes/config-array" "^0.9.2"
     ajv "^6.10.0"
     chalk "^4.0.0"
     cross-spawn "^7.0.2"
-    debug "^4.0.1"
+    debug "^4.3.2"
     doctrine "^3.0.0"
-    enquirer "^2.3.5"
     escape-string-regexp "^4.0.0"
-    eslint-scope "^5.1.1"
-    eslint-utils "^2.1.0"
-    eslint-visitor-keys "^2.0.0"
-    espree "^7.3.1"
+    eslint-scope "^7.1.1"
+    eslint-utils "^3.0.0"
+    eslint-visitor-keys "^3.3.0"
+    espree "^9.3.2"
     esquery "^1.4.0"
     esutils "^2.0.2"
     fast-deep-equal "^3.1.3"
     file-entry-cache "^6.0.1"
     functional-red-black-tree "^1.0.1"
-    glob-parent "^5.1.2"
-    globals "^13.6.0"
-    ignore "^4.0.6"
+    glob-parent "^6.0.1"
+    globals "^13.15.0"
+    ignore "^5.2.0"
     import-fresh "^3.0.0"
     imurmurhash "^0.1.4"
     is-glob "^4.0.0"
-    js-yaml "^3.13.1"
+    js-yaml "^4.1.0"
     json-stable-stringify-without-jsonify "^1.0.1"
     levn "^0.4.1"
     lodash.merge "^4.6.2"
-    minimatch "^3.0.4"
+    minimatch "^3.1.2"
     natural-compare "^1.4.0"
     optionator "^0.9.1"
-    progress "^2.0.0"
-    regexpp "^3.1.0"
-    semver "^7.2.1"
-    strip-ansi "^6.0.0"
+    regexpp "^3.2.0"
+    strip-ansi "^6.0.1"
     strip-json-comments "^3.1.0"
-    table "^6.0.9"
     text-table "^0.2.0"
     v8-compile-cache "^2.0.3"
 
-espree@^7.3.0, espree@^7.3.1:
-  version "7.3.1"
-  resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6"
-  integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==
+espree@^9.3.2:
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596"
+  integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==
   dependencies:
-    acorn "^7.4.0"
-    acorn-jsx "^5.3.1"
-    eslint-visitor-keys "^1.3.0"
+    acorn "^8.7.1"
+    acorn-jsx "^5.3.2"
+    eslint-visitor-keys "^3.3.0"
 
 esprima@^4.0.0:
   version "4.0.1"
@@ -3022,9 +3427,9 @@ estraverse@^4.1.1:
   integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
 
 estraverse@^5.1.0, estraverse@^5.2.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
-  integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+  integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
 
 esutils@^2.0.2:
   version "2.0.3"
@@ -3074,43 +3479,96 @@ execa@^5.0.0:
     signal-exit "^3.0.3"
     strip-final-newline "^2.0.0"
 
+execa@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20"
+  integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA==
+  dependencies:
+    cross-spawn "^7.0.3"
+    get-stream "^6.0.1"
+    human-signals "^3.0.1"
+    is-stream "^3.0.0"
+    merge-stream "^2.0.0"
+    npm-run-path "^5.1.0"
+    onetime "^6.0.0"
+    signal-exit "^3.0.7"
+    strip-final-newline "^3.0.0"
+
 exenv@^1.2.1:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
   integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=
 
-express@^4.17.1, express@~4.17.1:
-  version "4.17.1"
-  resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
-  integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+express@^4.17.3:
+  version "4.18.0"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.18.0.tgz#7a426773325d0dd5406395220614c0db10b6e8e2"
+  integrity sha512-EJEXxiTQJS3lIPrU1AE2vRuT7X7E+0KBbpm5GSoK524yl0K8X+er8zS2P14E64eqsVNoWbMCT7MpmQ+ErAhgRg==
   dependencies:
-    accepts "~1.3.7"
+    accepts "~1.3.8"
     array-flatten "1.1.1"
-    body-parser "1.19.0"
-    content-disposition "0.5.3"
+    body-parser "1.20.0"
+    content-disposition "0.5.4"
     content-type "~1.0.4"
-    cookie "0.4.0"
+    cookie "0.5.0"
     cookie-signature "1.0.6"
     debug "2.6.9"
-    depd "~1.1.2"
+    depd "2.0.0"
     encodeurl "~1.0.2"
     escape-html "~1.0.3"
     etag "~1.8.1"
-    finalhandler "~1.1.2"
+    finalhandler "1.2.0"
     fresh "0.5.2"
+    http-errors "2.0.0"
     merge-descriptors "1.0.1"
     methods "~1.1.2"
-    on-finished "~2.3.0"
+    on-finished "2.4.1"
     parseurl "~1.3.3"
     path-to-regexp "0.1.7"
-    proxy-addr "~2.0.5"
-    qs "6.7.0"
+    proxy-addr "~2.0.7"
+    qs "6.10.3"
     range-parser "~1.2.1"
-    safe-buffer "5.1.2"
-    send "0.17.1"
-    serve-static "1.14.1"
-    setprototypeof "1.1.1"
-    statuses "~1.5.0"
+    safe-buffer "5.2.1"
+    send "0.18.0"
+    serve-static "1.15.0"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
+express@~4.18.1:
+  version "4.18.1"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.18.1.tgz#7797de8b9c72c857b9cd0e14a5eea80666267caf"
+  integrity sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==
+  dependencies:
+    accepts "~1.3.8"
+    array-flatten "1.1.1"
+    body-parser "1.20.0"
+    content-disposition "0.5.4"
+    content-type "~1.0.4"
+    cookie "0.5.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "2.0.0"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "1.2.0"
+    fresh "0.5.2"
+    http-errors "2.0.0"
+    merge-descriptors "1.0.1"
+    methods "~1.1.2"
+    on-finished "2.4.1"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.7"
+    proxy-addr "~2.0.7"
+    qs "6.10.3"
+    range-parser "~1.2.1"
+    safe-buffer "5.2.1"
+    send "0.18.0"
+    serve-static "1.15.0"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
     type-is "~1.6.18"
     utils-merge "1.0.1"
     vary "~1.1.2"
@@ -3126,9 +3584,9 @@ extsprintf@1.3.0:
   integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
 
 extsprintf@^1.2.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
-  integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
+  integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
 
 fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
   version "3.1.3"
@@ -3140,10 +3598,21 @@ fast-diff@^1.1.2:
   resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
   integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
 
-fast-glob@^3.0.3, fast-glob@^3.1.1, fast-glob@^3.2.5:
-  version "3.2.7"
-  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
-  integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
+fast-glob@^3.0.3, fast-glob@^3.2.9:
+  version "3.2.10"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.10.tgz#2734f83baa7f43b7fd41e13bc34438f4ffe284ee"
+  integrity sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
+fast-glob@^3.2.11:
+  version "3.2.11"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
+  integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
   dependencies:
     "@nodelib/fs.stat" "^2.0.2"
     "@nodelib/fs.walk" "^1.2.3"
@@ -3167,9 +3636,9 @@ fastest-levenshtein@^1.0.12:
   integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
 
 fastq@^1.6.0:
-  version "1.12.0"
-  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.12.0.tgz#ed7b6ab5d62393fb2cc591c853652a5c318bf794"
-  integrity sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
+  integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
   dependencies:
     reusify "^1.0.4"
 
@@ -3204,23 +3673,23 @@ filter-obj@^1.1.0:
   resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
   integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs=
 
-finalhandler@~1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
-  integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+finalhandler@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
+  integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
   dependencies:
     debug "2.6.9"
     encodeurl "~1.0.2"
     escape-html "~1.0.3"
-    on-finished "~2.3.0"
+    on-finished "2.4.1"
     parseurl "~1.3.3"
-    statuses "~1.5.0"
+    statuses "2.0.1"
     unpipe "~1.0.0"
 
 find-cache-dir@^3.3.1:
-  version "3.3.1"
-  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.1.tgz#89b33fad4a4670daa94f855f7fbe31d6d84fe880"
-  integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b"
+  integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==
   dependencies:
     commondir "^1.0.1"
     make-dir "^3.0.2"
@@ -3255,7 +3724,7 @@ find-up@^3.0.0:
   dependencies:
     locate-path "^3.0.0"
 
-find-up@^4.0.0, find-up@^4.1.0:
+find-up@^4.0.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
   integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
@@ -3272,9 +3741,9 @@ flat-cache@^3.0.4:
     rimraf "^3.0.2"
 
 flatted@^3.1.0:
-  version "3.2.2"
-  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561"
-  integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2"
+  integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==
 
 flush-write-stream@^1.0.0:
   version "1.1.1"
@@ -3285,9 +3754,9 @@ flush-write-stream@^1.0.0:
     readable-stream "^2.3.6"
 
 follow-redirects@^1.0.0:
-  version "1.14.2"
-  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.2.tgz#cecb825047c00f5e66b142f90fed4f515dec789b"
-  integrity sha512-yLR6WaE2lbF0x4K2qE2p9PEXKLDjUjnR/xmjS3wHAYxtlsI9MLLBJUZirAHKzUZDGLxje7w/cXR49WOUo4rbsA==
+  version "1.14.7"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
+  integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
 
 forever-agent@~0.6.1:
   version "0.6.1"
@@ -3345,13 +3814,6 @@ fs-minipass@^1.2.7:
   dependencies:
     minipass "^2.6.0"
 
-fs-minipass@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
-  integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
-  dependencies:
-    minipass "^3.0.0"
-
 fs-monkey@1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.3.tgz#ae3ac92d53bb328efe0e9a1d9541f6ad8d48e2d3"
@@ -3406,10 +3868,10 @@ functional-red-black-tree@^1.0.1:
   resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
   integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
 
-fuse.js@^3.4.5:
-  version "3.6.1"
-  resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.6.1.tgz#7de85fdd6e1b3377c23ce010892656385fd9b10c"
-  integrity sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==
+fuse.js@^6.5.3:
+  version "6.5.3"
+  resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-6.5.3.tgz#7446c0acbc4ab0ab36fa602e97499bdb69452b93"
+  integrity sha512-sA5etGE7yD/pOqivZRBvUBd/NaL2sjAu6QuSaFoe1H2BrJSkH/T/UXAJ8CdXdw7DvY3Hs8CXKYkDWX7RiP5KOg==
 
 gauge@~2.7.3:
   version "2.7.4"
@@ -3425,13 +3887,6 @@ gauge@~2.7.3:
     strip-ansi "^3.0.1"
     wide-align "^1.1.0"
 
-gaze@^1.0.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
-  integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
-  dependencies:
-    globule "^1.0.0"
-
 genfun@^5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537"
@@ -3478,26 +3933,24 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
     has "^1.0.3"
     has-symbols "^1.0.1"
 
-get-own-enumerable-property-symbols@^3.0.0:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
-  integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
-
-get-stdin@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
-  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
-
 get-stream@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
   integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
 
-get-stream@^6.0.0:
+get-stream@^6.0.0, get-stream@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
   integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
 
+get-symbol-description@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6"
+  integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==
+  dependencies:
+    call-bind "^1.0.2"
+    get-intrinsic "^1.1.1"
+
 getpass@^0.1.1:
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
@@ -3517,19 +3970,31 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
   dependencies:
     is-glob "^4.0.1"
 
-glob-parent@^6.0.0:
-  version "6.0.1"
-  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.1.tgz#42054f685eb6a44e7a7d189a96efa40a54971aa7"
-  integrity sha512-kEVjS71mQazDBHKcsq4E9u/vUzaLcw1A8EtUeydawvIWQCJM0qQ08G1H7/XTjFUulla6XQiDOG6MXSaG0HDKog==
+glob-parent@^6.0.1:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+  integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
   dependencies:
-    is-glob "^4.0.1"
+    is-glob "^4.0.3"
 
 glob-to-regexp@^0.4.1:
   version "0.4.1"
   resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
   integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
 
-glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1, glob@~7.1.2:
+glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023"
+  integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@~7.1.2:
   version "7.1.7"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90"
   integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==
@@ -3553,10 +4018,10 @@ globals@^11.1.0:
   resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
   integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
 
-globals@^13.6.0, globals@^13.9.0:
-  version "13.11.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-13.11.0.tgz#40ef678da117fe7bd2e28f1fab24951bd0255be7"
-  integrity sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==
+globals@^13.15.0:
+  version "13.17.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-13.17.0.tgz#902eb1e680a41da93945adbdcb5a9f361ba69bd4"
+  integrity sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==
   dependencies:
     type-fest "^0.20.2"
 
@@ -3574,18 +4039,29 @@ globby@10.0.0:
     merge2 "^1.2.3"
     slash "^3.0.0"
 
-globby@^11.0.1, globby@^11.0.3:
-  version "11.0.4"
-  resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5"
-  integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==
+globby@^11.1.0:
+  version "11.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+  integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
   dependencies:
     array-union "^2.1.0"
     dir-glob "^3.0.1"
-    fast-glob "^3.1.1"
-    ignore "^5.1.4"
-    merge2 "^1.3.0"
+    fast-glob "^3.2.9"
+    ignore "^5.2.0"
+    merge2 "^1.4.1"
     slash "^3.0.0"
 
+globby@^13.1.1:
+  version "13.1.2"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.2.tgz#29047105582427ab6eca4f905200667b056da515"
+  integrity sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==
+  dependencies:
+    dir-glob "^3.0.1"
+    fast-glob "^3.2.11"
+    ignore "^5.2.0"
+    merge2 "^1.4.1"
+    slash "^4.0.0"
+
 globby@^6.1.0:
   version "6.1.0"
   resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
@@ -3597,15 +4073,6 @@ globby@^6.1.0:
     pify "^2.0.0"
     pinkie-promise "^2.0.0"
 
-globule@^1.0.0:
-  version "1.3.3"
-  resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.3.tgz#811919eeac1ab7344e905f2e3be80a13447973c2"
-  integrity sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==
-  dependencies:
-    glob "~7.1.1"
-    lodash "~4.17.10"
-    minimatch "~3.0.2"
-
 got@^6.7.1:
   version "6.7.1"
   resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -3623,10 +4090,10 @@ got@^6.7.1:
     unzip-response "^2.0.1"
     url-parse-lax "^1.0.0"
 
-graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.3, graceful-fs@^4.2.4, graceful-fs@^4.2.6:
-  version "4.2.8"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
-  integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
+  version "4.2.9"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96"
+  integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==
 
 graceful-fs@~4.1.11:
   version "4.1.15"
@@ -3651,18 +4118,6 @@ har-validator@~5.1.3:
     ajv "^6.12.3"
     har-schema "^2.0.0"
 
-hard-rejection@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
-  integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
-
-has-ansi@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
-  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
-  dependencies:
-    ansi-regex "^2.0.0"
-
 has-bigints@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
@@ -3724,13 +4179,6 @@ hosted-git-info@^2.1.4, hosted-git-info@^2.6.0, hosted-git-info@^2.7.1:
   resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
   integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
 
-hosted-git-info@^4.0.1:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961"
-  integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==
-  dependencies:
-    lru-cache "^6.0.0"
-
 hpack.js@^2.1.6:
   version "2.1.6"
   resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
@@ -3763,16 +4211,16 @@ http-deceiver@^1.2.7:
   resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
   integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
 
-http-errors@1.7.2:
-  version "1.7.2"
-  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
-  integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+http-errors@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+  integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
   dependencies:
-    depd "~1.1.2"
-    inherits "2.0.3"
-    setprototypeof "1.1.1"
-    statuses ">= 1.5.0 < 2"
-    toidentifier "1.0.0"
+    depd "2.0.0"
+    inherits "2.0.4"
+    setprototypeof "1.2.0"
+    statuses "2.0.1"
+    toidentifier "1.0.1"
 
 http-errors@~1.6.2:
   version "1.6.3"
@@ -3784,21 +4232,10 @@ http-errors@~1.6.2:
     setprototypeof "1.1.0"
     statuses ">= 1.4.0 < 2"
 
-http-errors@~1.7.2:
-  version "1.7.3"
-  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
-  integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
-  dependencies:
-    depd "~1.1.2"
-    inherits "2.0.4"
-    setprototypeof "1.1.1"
-    statuses ">= 1.5.0 < 2"
-    toidentifier "1.0.0"
-
 http-parser-js@>=0.5.1:
-  version "0.5.3"
-  resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9"
-  integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==
+  version "0.5.5"
+  resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.5.tgz#d7c30d5d3c90d865b4a2e870181f9d6f22ac7ac5"
+  integrity sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==
 
 http-proxy-agent@^2.0.0, http-proxy-agent@^2.1.0:
   version "2.1.0"
@@ -3808,12 +4245,12 @@ http-proxy-agent@^2.0.0, http-proxy-agent@^2.1.0:
     agent-base "4"
     debug "3.1.0"
 
-http-proxy-middleware@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz#7ef3417a479fb7666a571e09966c66a39bd2c15f"
-  integrity sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg==
+http-proxy-middleware@^2.0.3:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f"
+  integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==
   dependencies:
-    "@types/http-proxy" "^1.17.5"
+    "@types/http-proxy" "^1.17.8"
     http-proxy "^1.18.1"
     is-glob "^4.0.1"
     is-plain-obj "^3.0.0"
@@ -3850,6 +4287,11 @@ human-signals@^2.1.0:
   resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
   integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
 
+human-signals@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5"
+  integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ==
+
 humanize-ms@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed"
@@ -3857,17 +4299,17 @@ humanize-ms@^1.2.1:
   dependencies:
     ms "^2.0.0"
 
-husky@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.1.tgz#579f4180b5da4520263e8713cc832942b48e1f1c"
-  integrity sha512-gceRaITVZ+cJH9sNHqx5tFwbzlLCVxtVZcusME8JYQ8Edy5mpGDOqD8QBCdMhpyo9a+JXddnujQ4rpY2Ff9SJA==
+husky@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9"
+  integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw==
 
-i18next@^20.3.3:
-  version "20.4.0"
-  resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.4.0.tgz#6897229a7898e23f3c4885f10315c978b594d3b9"
-  integrity sha512-89iWWJudmaHJwzIdJ/1eu98GtsJnwBhOUWwlAre70itPMuTE/NTPtgVeaS1CGaB8Q3XrYBGpEqlq4jsScDx9kg==
+i18next@^21.8.14:
+  version "21.8.14"
+  resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.8.14.tgz#03a3a669ef4520aadd9d152c80596f600e287c6a"
+  integrity sha512-4Yi+DtexvMm/Yw3Q9fllzY12SgLk+Mcmar+rCAccsOPul/2UmnBzoHbTGn/L48IPkFcmrNaH7xTLboBWIbH6pw==
   dependencies:
-    "@babel/runtime" "^7.12.0"
+    "@babel/runtime" "^7.17.2"
 
 iconv-lite@0.4.24:
   version "0.4.24"
@@ -3900,15 +4342,15 @@ ignore-walk@^3.0.1:
   dependencies:
     minimatch "^3.0.4"
 
-ignore@^4.0.6:
-  version "4.0.6"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
-  integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+ignore@^5.1.1, ignore@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
+  integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==
 
-ignore@^5.1.1, ignore@^5.1.4:
-  version "5.1.8"
-  resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
-  integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
+immutable@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
+  integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
 
 import-fresh@^2.0.0:
   version "2.0.0"
@@ -3932,9 +4374,9 @@ import-lazy@^2.1.0:
   integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
 
 import-local@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6"
-  integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"
+  integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==
   dependencies:
     pkg-dir "^4.2.0"
     resolve-cwd "^3.0.0"
@@ -4009,25 +4451,18 @@ infer-owner@^1.0.4:
   integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
 
 inferno-clone-vnode@^7.4.2:
-  version "7.4.8"
-  resolved "https://registry.yarnpkg.com/inferno-clone-vnode/-/inferno-clone-vnode-7.4.8.tgz#fafdb21f86e566f662da7e58ff9be1fc76baff08"
-  integrity sha512-Un9Saio4TJ+1DFehPd7JuNDJV2Fy2aPhK5hD4zmG+JWLUIphi/nuhbwrlsCNmTTDmOsB7GrqyrXFvOUEKX4YpA==
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-clone-vnode/-/inferno-clone-vnode-7.4.11.tgz#1bcce4ff6ac9ea2986766b17aee1d1a22b158558"
+  integrity sha512-6/newyzWO/lrwcA9q5DBAfslccPWqhpgrDQg/wWiHKZwRBe1kJjtiALsR+/1wLq1Z+YO3L1MPnlEnFu+nltUbA==
   dependencies:
-    inferno "7.4.8"
+    inferno "7.4.11"
 
-inferno-create-element@^7.4.2:
-  version "7.4.8"
-  resolved "https://registry.yarnpkg.com/inferno-create-element/-/inferno-create-element-7.4.8.tgz#77bbf24288645c359cf65b4821a3938c6537eb5e"
-  integrity sha512-hCkA+RAiqoeWlmmCrb3VIUDV+4lEeLDCI98RcB4HqzAJwjH8dMR4ZeDQO3f9crygPnmSW7r1L0Ykjf0O2oHYFQ==
+inferno-create-element@^7.4.11, inferno-create-element@^7.4.2:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-create-element/-/inferno-create-element-7.4.11.tgz#1690b3ad28b61be93765b11b409dc9a9a35bf63a"
+  integrity sha512-kE6XIx2hPAd5qpDli2iGjNXgubvuyxdLvoiW71WnSzIIxA+Uxa/s8lY8m03VyHHVypFV3n329ZY5dFvKc7UQMg==
   dependencies:
-    inferno "7.4.8"
-
-inferno-create-element@^7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno-create-element/-/inferno-create-element-7.4.9.tgz#0538b100442163e1c361f2a78664ee3dd5e6f2bb"
-  integrity sha512-wQ/gnd66pdrlm8uPAjGDlSCF6sX9mQ/mGtq8yYKHBTAmWPdE9P3mVsw5Wg9Iyy5NxRVsJqB9emBXIA8PNNkMCg==
-  dependencies:
-    inferno "7.4.9"
+    inferno "7.4.11"
 
 inferno-helmet@^5.2.1:
   version "5.2.1"
@@ -4038,16 +4473,17 @@ inferno-helmet@^5.2.1:
     inferno-side-effect "^1.1.5"
     object-assign "^4.1.1"
 
-inferno-hydrate@^7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno-hydrate/-/inferno-hydrate-7.4.9.tgz#ba355f2e17cc273d7adfd957bb19fce4447d8b29"
-  integrity sha512-QP8zmgTddI4WShmQO9VF+wqC3OXmwaGaZkQQNZsp7ZfprhhYuW6ulSPyckWEB/zGZxxYPdG8ZthEeQZF4NS5Jw==
+inferno-hydrate@^7.4.11:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-hydrate/-/inferno-hydrate-7.4.11.tgz#275027585268055f7d741c21978d7b5065169a3a"
+  integrity sha512-hF9Ke4GHAkj8GQrMXBZPfsUqhq6WjkoDCAfXhPBuF1Wiceqyy8KerOOXEnuocHky77fuEXq0AzVnQcC064Bkfw==
   dependencies:
-    inferno "7.4.9"
+    inferno "7.4.11"
 
-"inferno-i18next@github:nimbusec-oss/inferno-i18next#semver:^7.4.2":
-  version "7.4.2"
-  resolved "https://codeload.github.com/nimbusec-oss/inferno-i18next/tar.gz/54b9be591ccd62c53799ad23e35f17144a62f909"
+inferno-i18next-dess@^0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/inferno-i18next-dess/-/inferno-i18next-dess-0.0.1.tgz#48ae6bb4c3a617e59ff8dc97b9ed70f2ef762206"
+  integrity sha512-z/6UnuWFMyBivfR3SI9AmgA0/JvXARqtG/9BQryaLPenlG7iAb4cN2TeSt0mHIgFOo01QHVWZ8dqn7jZRijp2Q==
   dependencies:
     html-parse-stringify2 "^2.0.1"
     inferno "^7.4.2"
@@ -4056,32 +4492,27 @@ inferno-hydrate@^7.4.9:
     inferno-shared "^7.4.2"
     inferno-vnode-flags "^7.4.2"
 
-inferno-router@^7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.4.9.tgz#6f3d708f8e01d47f982b41ae18c9312a4c51220b"
-  integrity sha512-MunV594oIw0lGjcf6HMyPIx/F5bsz2+nz+ao4Jd6cLWy1zUCD8eowqCfZe3Re82wbW8+w7zNp5bCpuV+4IiWNQ==
+inferno-router@^7.4.11:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-router/-/inferno-router-7.4.11.tgz#80bd47bf7c059a219cad9f3857585023fd55781f"
+  integrity sha512-7H5OTpoxGjRl2wtF1exFdlFVmO3k6EhNm0yMSfk34DOEEDqiIpy0QiWx0Q0nn7Mm2Wddgdt31RAl69/k/GuBYA==
   dependencies:
     history "^4.10.1"
     hoist-non-inferno-statics "^1.1.3"
-    inferno "7.4.9"
+    inferno "7.4.11"
     path-to-regexp-es6 "1.7.0"
 
-inferno-server@^7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno-server/-/inferno-server-7.4.9.tgz#05e73aa14512f492d9eec30698c55f30c39493bb"
-  integrity sha512-x9kE+Tk34QfRM1OL4+KSWY86t7dLVanRhDWikBs3jsHuFU+bQ9VGuEp4cf4wEBnv0DbPQiH+/XY5aoaQ6S8zFQ==
+inferno-server@^7.4.11:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-server/-/inferno-server-7.4.11.tgz#05ec0f7ceea4a30da412baaccbbfeca258db27cf"
+  integrity sha512-SUnkCqZNWOIrjRVoVk/E1/70O1f1ImkCX9H2gDPbS0uc3GDxuzIeCgn0rpcc0XV9KzZJ2LTGxuBtEoQQOjUn2Q==
   dependencies:
-    inferno "7.4.9"
-
-inferno-shared@7.4.8, inferno-shared@^7.4.2:
-  version "7.4.8"
-  resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.8.tgz#2b554a36683b770339008749096d9704846dd337"
-  integrity sha512-I0jnqsBcQvGJ7hqZF3vEzspQ80evViCe8joP3snWkPXPElk9WBVGLBHX5tHwuFuXv6wW4zeVVA4kBRAs47B+NQ==
+    inferno "7.4.11"
 
-inferno-shared@7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.9.tgz#f3cc5e85adadd7471a5e1c72da7df93a0bb98340"
-  integrity sha512-WNBz7OJ1DiVN+NeHgflwBHqvD589B9xMPkFGTj6mNs1cQCxYIZtslp5cqpkEo5TnA8O3FgEF00LMaLfc/i8fyw==
+inferno-shared@7.4.11, inferno-shared@^7.4.2:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-shared/-/inferno-shared-7.4.11.tgz#6e06e0668c4dad5f8b1fd4c688e1072faa6f1e87"
+  integrity sha512-pN725bDSTxkQmRS3e/3H02/xAqgHl+xgddCMjPm8M0etRdRcVCisi3NGPhzSbDDmiftrxhY31exs7+dwsngcDA==
 
 inferno-side-effect@^1.1.5:
   version "1.1.5"
@@ -4092,32 +4523,18 @@ inferno-side-effect@^1.1.5:
     npm "^5.8.0"
     shallowequal "^1.0.1"
 
-inferno-vnode-flags@7.4.8, inferno-vnode-flags@^7.4.2:
-  version "7.4.8"
-  resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.8.tgz#275d70e3c8b2b3f4eb56041cc9b8c832ce1fb26d"
-  integrity sha512-wOUeO7Aho8VH+s2V2K/53KwS0DtQFgT7TdzPE/s6P26ZIxQj+vt7oTJqzXn+xjRIjnfkTLm2eQ8qfInOWCu1rw==
-
-inferno-vnode-flags@7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.9.tgz#26fe1a40f00de2ebc05b9e7543c8577c674c074b"
-  integrity sha512-pIGvc1MRSRrvjAOpARRz9OCyGrODKYfhw02ctWTIt3Jtn8dyqsjV0ZIaXOQEjpCi5ii7yfE5xwI+ZRI/g3pviQ==
-
-inferno@7.4.8, inferno@^7.4.2:
-  version "7.4.8"
-  resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.8.tgz#0d5504753e79903b0e4bbeff76fc11fd0b9ffe92"
-  integrity sha512-4XwGe5Kd0QkSaM/jqAQWjM0GfDLv+KujcWm5zbIow80G1tOEnZurQqhyF8u6m/HX3SnrCi+njlVdtPKDJXQiDw==
-  dependencies:
-    inferno-shared "7.4.8"
-    inferno-vnode-flags "7.4.8"
-    opencollective-postinstall "^2.0.3"
+inferno-vnode-flags@7.4.11, inferno-vnode-flags@^7.4.2:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno-vnode-flags/-/inferno-vnode-flags-7.4.11.tgz#642a835a8dde514f244296b27c176a2b8704fbac"
+  integrity sha512-L7lslEQCq3IfwgT/b9zhuMf8fv6KXCNXXHZevk/WYxnqJsOWGDcKpJn0zkzXfvmj0otbB149iLUQVBq3oe2sfA==
 
-inferno@7.4.9, inferno@^7.4.9:
-  version "7.4.9"
-  resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.9.tgz#3722319b53b7e902ab194ad26fa6e80332d85c47"
-  integrity sha512-YxUYo3CyFGRkeSne87DacSAV1yXOp6dAu0toaEkwxb4dIIMilxDmJ8ap0EKxr3ZnQpX7EKmGrLBXrkYQVcmfvg==
+inferno@7.4.11, inferno@^7.4.11, inferno@^7.4.2:
+  version "7.4.11"
+  resolved "https://registry.yarnpkg.com/inferno/-/inferno-7.4.11.tgz#fcee308cf0e4a2f6066d96da74e3b425583bfc66"
+  integrity sha512-N+cs33ESWI8fdToCd98yMRYl7jkLnCkJskxov3FKKlaKOvk3PRlAttbhmUaYdWXlRvt2WeXi+J4MbzNj3V6G0w==
   dependencies:
-    inferno-shared "7.4.9"
-    inferno-vnode-flags "7.4.9"
+    inferno-shared "7.4.11"
+    inferno-vnode-flags "7.4.11"
     opencollective-postinstall "^2.0.3"
 
 inflight@^1.0.4, inflight@~1.0.6:
@@ -4157,16 +4574,6 @@ init-package-json@^1.10.3:
     validate-npm-package-license "^3.0.1"
     validate-npm-package-name "^3.0.0"
 
-internal-ip@^6.2.0:
-  version "6.2.0"
-  resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-6.2.0.tgz#d5541e79716e406b74ac6b07b856ef18dc1621c1"
-  integrity sha512-D8WGsR6yDt8uq7vDMu7mjcR+yRMm3dW8yufyChmszWRjcSHuxLBkR3GdS2HZAjodsaGuCvXeEJpueisXJULghg==
-  dependencies:
-    default-gateway "^6.0.0"
-    ipaddr.js "^1.9.1"
-    is-ip "^3.1.0"
-    p-event "^4.2.0"
-
 internal-slot@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
@@ -4186,17 +4593,12 @@ invert-kv@^1.0.0:
   resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6"
   integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
 
-ip-regex@^4.0.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5"
-  integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==
-
-ip@1.1.5, ip@^1.1.0, ip@^1.1.4:
+ip@1.1.5, ip@^1.1.4:
   version "1.1.5"
   resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
   integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
 
-ipaddr.js@1.9.1, ipaddr.js@^1.9.1:
+ipaddr.js@1.9.1:
   version "1.9.1"
   resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
   integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
@@ -4255,7 +4657,7 @@ is-builtin-module@^3.0.0:
   dependencies:
     builtin-modules "^3.0.0"
 
-is-callable@^1.1.4, is-callable@^1.2.3:
+is-callable@^1.1.4, is-callable@^1.2.4:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
   integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
@@ -4274,10 +4676,10 @@ is-cidr@~1.0.0:
   dependencies:
     cidr-regex "1.0.6"
 
-is-core-module@^2.2.0, is-core-module@^2.5.0:
-  version "2.6.0"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19"
-  integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==
+is-core-module@^2.8.0:
+  version "2.8.1"
+  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211"
+  integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==
   dependencies:
     has "^1.0.3"
 
@@ -4320,10 +4722,15 @@ is-fullwidth-code-point@^3.0.0:
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
   integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
 
-is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
-  integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+is-fullwidth-code-point@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88"
+  integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
   dependencies:
     is-extglob "^2.1.1"
 
@@ -4335,17 +4742,10 @@ is-installed-globally@^0.1.0:
     global-dirs "^0.1.0"
     is-path-inside "^1.0.0"
 
-is-ip@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8"
-  integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==
-  dependencies:
-    ip-regex "^4.0.0"
-
 is-negative-zero@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
-  integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
+  integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
 
 is-npm@^1.0.0:
   version "1.0.0"
@@ -4364,12 +4764,12 @@ is-number@^7.0.0:
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 
-is-obj@^1.0.0, is-obj@^1.0.1:
+is-obj@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
   integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
 
-is-path-cwd@^2.0.0, is-path-cwd@^2.2.0:
+is-path-cwd@^2.0.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
   integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
@@ -4395,21 +4795,11 @@ is-path-inside@^2.1.0:
   dependencies:
     path-is-inside "^1.0.2"
 
-is-path-inside@^3.0.2:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
-  integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
-
 is-plain-obj@2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
   integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
 
-is-plain-obj@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
-  integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
-
 is-plain-obj@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7"
@@ -4427,7 +4817,7 @@ is-redirect@^1.0.0:
   resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
   integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
 
-is-regex@^1.0.4, is-regex@^1.1.3:
+is-regex@^1.0.4, is-regex@^1.1.4:
   version "1.1.4"
   resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958"
   integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==
@@ -4435,16 +4825,16 @@ is-regex@^1.0.4, is-regex@^1.1.3:
     call-bind "^1.0.2"
     has-tostringtag "^1.0.0"
 
-is-regexp@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
-  integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk=
-
 is-retry-allowed@^1.0.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
   integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
 
+is-shared-array-buffer@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6"
+  integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==
+
 is-stream@^1.0.0, is-stream@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
@@ -4455,7 +4845,12 @@ is-stream@^2.0.0:
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
   integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
 
-is-string@^1.0.5, is-string@^1.0.6:
+is-stream@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
+  integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
+
+is-string@^1.0.5, is-string@^1.0.7:
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd"
   integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==
@@ -4474,10 +4869,12 @@ is-typedarray@~1.0.0:
   resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
   integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
 
-is-unicode-supported@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
-  integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+is-weakref@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2"
+  integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==
+  dependencies:
+    call-bind "^1.0.2"
 
 is-wsl@^2.2.0:
   version "2.2.0"
@@ -4501,11 +4898,6 @@ isexe@^2.0.0:
   resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
   integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
 
-iso-639-1@^2.1.9:
-  version "2.1.9"
-  resolved "https://registry.yarnpkg.com/iso-639-1/-/iso-639-1-2.1.9.tgz#e41b11d4f1808e5316d0252c3fa16eeb9b37bb58"
-  integrity sha512-owRu9up+Cpx/hwSzm83j6G8PtC7U99UCtPVItsafefNfEgMl+pi8KBwhXwJkJfp6IouyYWFxj8n24SvCWpKZEQ==
-
 isobject@^3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
@@ -4524,20 +4916,15 @@ isstream@~0.1.2:
   resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
   integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
 
-jest-worker@^27.0.2:
-  version "27.0.6"
-  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.0.6.tgz#a5fdb1e14ad34eb228cfe162d9f729cdbfa28aed"
-  integrity sha512-qupxcj/dRuA3xHPMUd40gr2EaAurFbkwzOh7wfPaeE9id7hyjURRQoqNfHifHK3XjJU6YJJUQKILGUnwGPEOCA==
+jest-worker@^27.4.1:
+  version "27.4.6"
+  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e"
+  integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==
   dependencies:
     "@types/node" "*"
     merge-stream "^2.0.0"
     supports-color "^8.0.0"
 
-js-base64@^2.1.8:
-  version "2.6.4"
-  resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4"
-  integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==
-
 "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -4551,6 +4938,13 @@ js-yaml@^3.13.1:
     argparse "^1.0.7"
     esprima "^4.0.0"
 
+js-yaml@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+  integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+  dependencies:
+    argparse "^2.0.1"
+
 jsbn@~0.1.0:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
@@ -4571,7 +4965,7 @@ json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-bet
   resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
   integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
 
-json-parse-even-better-errors@^2.3.0:
+json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
   integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
@@ -4586,10 +4980,10 @@ json-schema-traverse@^1.0.0:
   resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
   integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
 
-json-schema@0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
-  integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+json-schema@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
+  integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
 
 json-stable-stringify-without-jsonify@^1.0.1:
   version "1.0.1"
@@ -4601,13 +4995,6 @@ json-stringify-safe@~5.0.1:
   resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
   integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
 
-json5@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
-  integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
-  dependencies:
-    minimist "^1.2.0"
-
 json5@^2.1.2:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
@@ -4615,19 +5002,24 @@ json5@^2.1.2:
   dependencies:
     minimist "^1.2.5"
 
+json5@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
+  integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
+
 jsonparse@^1.2.0:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
   integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
 
 jsprim@^1.2.2:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
-  integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+  version "1.4.2"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
+  integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==
   dependencies:
     assert-plus "1.0.0"
     extsprintf "1.3.0"
-    json-schema "0.2.3"
+    json-schema "0.4.0"
     verror "1.10.0"
 
 jwt-decode@^3.1.2:
@@ -4635,15 +5027,15 @@ jwt-decode@^3.1.2:
   resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-3.1.2.tgz#3fb319f3675a2df0c2895c8f5e9fa4b67b04ed59"
   integrity sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==
 
-kind-of@^6.0.2, kind-of@^6.0.3:
+kind-of@^6.0.2:
   version "6.0.3"
   resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
   integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
 
 klona@^2.0.4:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
-  integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.5.tgz#d166574d90076395d9963aa7a928fabb8d76afbc"
+  integrity sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==
 
 latest-version@^3.0.0:
   version "3.1.0"
@@ -4664,10 +5056,10 @@ lcid@^1.0.0:
   dependencies:
     invert-kv "^1.0.0"
 
-lemmy-js-client@0.12.0:
-  version "0.12.0"
-  resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.12.0.tgz#2337aca9d8b38d92908d7f7a9479f0066a9eaeae"
-  integrity sha512-PSebUBkojM7OUlfSXKQhL4IcYKaKF+Xj2G0+pybaCvP9sJvviy32qHUi9BQeIhRHXgw8ILRH0Y+xZGKu0a3wvQ==
+lemmy-js-client@0.17.0-rc.43:
+  version "0.17.0-rc.43"
+  resolved "https://registry.yarnpkg.com/lemmy-js-client/-/lemmy-js-client-0.17.0-rc.43.tgz#30e985365a93d72184646fdfe359f39ccc2e2091"
+  integrity sha512-/+TOTZazoi74zwc8H2AJMd/Znrdnqfi0+TrfnmqvQ3fzrOl741ojEURxAHw3NsgW9b8HkubXZFLsi1RVR99UqA==
 
 levn@^0.4.1:
   version "0.4.1"
@@ -4710,48 +5102,55 @@ libnpx@^10.2.0:
     y18n "^4.0.0"
     yargs "^14.2.3"
 
-lines-and-columns@^1.1.6:
-  version "1.1.6"
-  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
-  integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
+lilconfig@2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25"
+  integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg==
 
-linkify-it@^3.0.1:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.2.tgz#f55eeb8bc1d3ae754049e124ab3bb56d97797fb8"
-  integrity sha512-gDBO4aHNZS6coiZCKVhSNh43F9ioIL4JwRjLZPkoLIY4yZFwg264Y5lu2x6rb1Js42Gh6Yqm2f6L2AJcnkzinQ==
+linkify-it@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.2.0.tgz#e3b54697e78bf915c70a38acd78fd09e0058b1cf"
+  integrity sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==
   dependencies:
     uc.micro "^1.0.1"
 
-lint-staged@^11.0.1:
-  version "11.1.2"
-  resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.1.2.tgz#4dd78782ae43ee6ebf2969cad9af67a46b33cd90"
-  integrity sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w==
+linkify-it@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-4.0.1.tgz#01f1d5e508190d06669982ba31a7d9f56a5751ec"
+  integrity sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==
   dependencies:
-    chalk "^4.1.1"
-    cli-truncate "^2.1.0"
-    commander "^7.2.0"
-    cosmiconfig "^7.0.0"
-    debug "^4.3.1"
-    enquirer "^2.3.6"
-    execa "^5.0.0"
-    listr2 "^3.8.2"
-    log-symbols "^4.1.0"
-    micromatch "^4.0.4"
+    uc.micro "^1.0.1"
+
+lint-staged@^13.0.3:
+  version "13.0.3"
+  resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.0.3.tgz#d7cdf03a3830b327a2b63c6aec953d71d9dc48c6"
+  integrity sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug==
+  dependencies:
+    cli-truncate "^3.1.0"
+    colorette "^2.0.17"
+    commander "^9.3.0"
+    debug "^4.3.4"
+    execa "^6.1.0"
+    lilconfig "2.0.5"
+    listr2 "^4.0.5"
+    micromatch "^4.0.5"
     normalize-path "^3.0.0"
-    please-upgrade-node "^3.2.0"
-    string-argv "0.3.1"
-    stringify-object "^3.3.0"
+    object-inspect "^1.12.2"
+    pidtree "^0.6.0"
+    string-argv "^0.3.1"
+    yaml "^2.1.1"
 
-listr2@^3.8.2:
-  version "3.11.0"
-  resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.11.0.tgz#9771b02407875aa78e73d6e0ff6541bbec0aaee9"
-  integrity sha512-XLJVe2JgXCyQTa3FbSv11lkKExYmEyA4jltVo8z4FX10Vt1Yj8IMekBfwim0BSOM9uj1QMTJvDQQpHyuPbB/dQ==
+listr2@^4.0.5:
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5"
+  integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==
   dependencies:
     cli-truncate "^2.1.0"
-    colorette "^1.2.2"
+    colorette "^2.0.16"
     log-update "^4.0.0"
     p-map "^4.0.0"
-    rxjs "^6.6.7"
+    rfdc "^1.3.0"
+    rxjs "^7.5.5"
     through "^2.3.8"
     wrap-ansi "^7.0.0"
 
@@ -4770,14 +5169,14 @@ loader-runner@^4.2.0:
   resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384"
   integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==
 
-loader-utils@^1.4.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
-  integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
+loader-utils@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129"
+  integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==
   dependencies:
     big.js "^5.2.2"
     emojis-list "^3.0.0"
-    json5 "^1.0.1"
+    json5 "^2.1.2"
 
 locate-path@^2.0.0:
   version "2.0.0"
@@ -4836,7 +5235,7 @@ lodash._root@~3.0.0:
   resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692"
   integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=
 
-lodash.clonedeep@^4.5.0, lodash.clonedeep@~4.5.0:
+lodash.clonedeep@~4.5.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
   integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
@@ -4856,11 +5255,6 @@ lodash.pick@^4.4.0:
   resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
   integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
 
-lodash.truncate@^4.4.2:
-  version "4.4.2"
-  resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
-  integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
-
 lodash.union@~4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
@@ -4881,19 +5275,6 @@ lodash@^3.10.1:
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
   integrity sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=
 
-lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.15, lodash@~4.17.10:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
-  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-log-symbols@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
-  integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
-  dependencies:
-    chalk "^4.1.0"
-    is-unicode-supported "^0.1.0"
-
 log-update@^4.0.0:
   version "4.0.0"
   resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
@@ -5003,28 +5384,24 @@ make-fetch-happen@^3.0.0:
     socks-proxy-agent "^3.0.1"
     ssri "^5.2.4"
 
-map-age-cleaner@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
-  integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
-  dependencies:
-    p-defer "^1.0.0"
-
-map-obj@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
-  integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
-
-map-obj@^4.0.0:
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7"
-  integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ==
-
 markdown-it-container@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/markdown-it-container/-/markdown-it-container-3.0.0.tgz#1d19b06040a020f9a827577bb7dbf67aa5de9a5b"
   integrity sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw==
 
+markdown-it-footnote@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz#e0e4c0d67390a4c5f0c75f73be605c7c190ca4d8"
+  integrity sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==
+
+markdown-it-html5-embed@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/markdown-it-html5-embed/-/markdown-it-html5-embed-1.0.0.tgz#f36bedca1eb12ce4df2d53b5ec72f62ba5e094b3"
+  integrity sha512-SPgugO/1+/9sZcgxoxijoTHSUpCUgFCNe1MSuTmDxDkV6NQrVzMclhRMFgE/rcHO+2rhIg3U7Oy80XA/E8ytpg==
+  dependencies:
+    markdown-it "^8.4.0"
+    mimoza "~1.0.0"
+
 markdown-it-sub@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz#375fd6026eae7ddcb012497f6411195ea1e3afe8"
@@ -5035,14 +5412,25 @@ markdown-it-sup@^1.0.0:
   resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3"
   integrity sha1-y5yf+RpSVawI8/09YyhuFd8KH8M=
 
-markdown-it@^12.1.0:
-  version "12.2.0"
-  resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.2.0.tgz#091f720fd5db206f80de7a8d1f1a7035fd0d38db"
-  integrity sha512-Wjws+uCrVQRqOoJvze4HCqkKl1AsSh95iFAeQDwnyfxM09divCBSXlDR1uTvyUP3Grzpn4Ru8GeCxYPM8vkCQg==
+markdown-it@^13.0.1:
+  version "13.0.1"
+  resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-13.0.1.tgz#c6ecc431cacf1a5da531423fc6a42807814af430"
+  integrity sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==
   dependencies:
     argparse "^2.0.1"
-    entities "~2.1.0"
-    linkify-it "^3.0.1"
+    entities "~3.0.1"
+    linkify-it "^4.0.1"
+    mdurl "^1.0.1"
+    uc.micro "^1.0.5"
+
+markdown-it@^8.4.0:
+  version "8.4.2"
+  resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.4.2.tgz#386f98998dc15a37722aa7722084f4020bdd9b54"
+  integrity sha512-GcRz3AWTqSUphY3vsUqQSFMbgR38a4Lh3GWlHRh/7MRwz8mcu9n2IO7HOh+bXHrR9kOPDl5RNCaEsrneb+xhHQ==
+  dependencies:
+    argparse "^1.0.7"
+    entities "~1.1.1"
+    linkify-it "^2.0.0"
     mdurl "^1.0.1"
     uc.micro "^1.0.5"
 
@@ -5068,39 +5456,13 @@ mem@^1.1.0:
   dependencies:
     mimic-fn "^1.0.0"
 
-mem@^8.1.1:
-  version "8.1.1"
-  resolved "https://registry.yarnpkg.com/mem/-/mem-8.1.1.tgz#cf118b357c65ab7b7e0817bdf00c8062297c0122"
-  integrity sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==
-  dependencies:
-    map-age-cleaner "^0.1.3"
-    mimic-fn "^3.1.0"
-
-memfs@^3.2.2:
-  version "3.2.2"
-  resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.2.2.tgz#5de461389d596e3f23d48bb7c2afb6161f4df40e"
-  integrity sha512-RE0CwmIM3CEvpcdK3rZ19BC4E6hv9kADkMN5rPduRak58cNArWLi/9jFLsa4rhsjfVxMP3v0jO7FHXq7SvFY5Q==
+memfs@^3.4.1:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305"
+  integrity sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==
   dependencies:
     fs-monkey "1.0.3"
 
-meow@^9.0.0:
-  version "9.0.0"
-  resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364"
-  integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==
-  dependencies:
-    "@types/minimist" "^1.2.0"
-    camelcase-keys "^6.2.2"
-    decamelize "^1.2.0"
-    decamelize-keys "^1.1.0"
-    hard-rejection "^2.1.0"
-    minimist-options "4.1.0"
-    normalize-package-data "^3.0.0"
-    read-pkg-up "^7.0.1"
-    redent "^3.0.0"
-    trim-newlines "^3.0.0"
-    type-fest "^0.18.0"
-    yargs-parser "^20.2.3"
-
 merge-descriptors@1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
@@ -5111,7 +5473,7 @@ merge-stream@^2.0.0:
   resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
   integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
 
-merge2@^1.2.3, merge2@^1.3.0:
+merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
   integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
@@ -5129,17 +5491,37 @@ micromatch@^4.0.2, micromatch@^4.0.4:
     braces "^3.0.1"
     picomatch "^2.2.3"
 
-mime-db@1.49.0, "mime-db@>= 1.43.0 < 2":
-  version "1.49.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed"
-  integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA==
+micromatch@^4.0.5:
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
+  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
+  dependencies:
+    braces "^3.0.2"
+    picomatch "^2.3.1"
+
+mime-db@1.51.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.6.0:
+  version "1.51.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c"
+  integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==
+
+mime-db@1.52.0:
+  version "1.52.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
 
 mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
-  version "2.1.32"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5"
-  integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==
+  version "2.1.34"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24"
+  integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==
+  dependencies:
+    mime-db "1.51.0"
+
+mime-types@~2.1.34:
+  version "2.1.35"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
   dependencies:
-    mime-db "1.49.0"
+    mime-db "1.52.0"
 
 mime@1.6.0:
   version "1.6.0"
@@ -5156,43 +5538,43 @@ mimic-fn@^2.1.0:
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
 
-mimic-fn@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74"
-  integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==
+mimic-fn@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
+  integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
 
-min-indent@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
-  integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
+mimoza@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/mimoza/-/mimoza-1.0.0.tgz#d74aa4fe08932f005e430bdc7bfcfa95fcab4e62"
+  integrity sha1-10qk/giTLwBeQwvce/z6lfyrTmI=
+  dependencies:
+    mime-db "^1.6.0"
 
-mini-css-extract-plugin@^2.1.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.2.0.tgz#48cb6d2bea8fa9eb36709856e003662eebb3eb92"
-  integrity sha512-91HeVHbq7PUJ4TwOuMTlFWfVWrLqf3SF0PlEDPV+wtgsfxrMebN9LLzflyQqdKLp4/H3PexRB1WLKsCqpWKkxQ==
+mini-css-extract-plugin@^2.6.1:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz#9a1251d15f2035c342d99a468ab9da7a0451b71e"
+  integrity sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==
   dependencies:
-    schema-utils "^3.1.0"
+    schema-utils "^4.0.0"
 
 minimalistic-assert@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
   integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
 
-minimatch@^3.0.4, minimatch@~3.0.2:
+minimatch@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
   integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
   dependencies:
     brace-expansion "^1.1.7"
 
-minimist-options@4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619"
-  integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==
+minimatch@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
   dependencies:
-    arrify "^1.0.1"
-    is-plain-obj "^1.1.0"
-    kind-of "^6.0.3"
+    brace-expansion "^1.1.7"
 
 minimist@^1.2.0, minimist@^1.2.5:
   version "1.2.5"
@@ -5207,13 +5589,6 @@ minipass@^2.3.3, minipass@^2.6.0, minipass@^2.9.0:
     safe-buffer "^5.1.2"
     yallist "^3.0.0"
 
-minipass@^3.0.0:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd"
-  integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==
-  dependencies:
-    yallist "^4.0.0"
-
 minizlib@^1.3.3:
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d"
@@ -5221,14 +5596,6 @@ minizlib@^1.3.3:
   dependencies:
     minipass "^2.9.0"
 
-minizlib@^2.1.1:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
-  integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
-  dependencies:
-    minipass "^3.0.0"
-    yallist "^4.0.0"
-
 mississippi@^1.2.0:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-1.3.1.tgz#2a8bb465e86550ac8b36a7b6f45599171d78671e"
@@ -5284,15 +5651,10 @@ mississippi@^3.0.0:
   dependencies:
     minimist "^1.2.5"
 
-mkdirp@^1.0.3:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
-  integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
-
-moment@^2.29.1:
-  version "2.29.1"
-  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
-  integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
+moment@^2.29.4:
+  version "2.29.4"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+  integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
 
 move-concurrently@^1.0.1:
   version "1.0.1"
@@ -5311,32 +5673,22 @@ ms@2.0.0:
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
   integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
 
-ms@2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
-  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
-
 ms@2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
   integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
 
-ms@^2.0.0, ms@^2.1.1:
+ms@2.1.3, ms@^2.0.0, ms@^2.1.1:
   version "2.1.3"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
   integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
 
-multicast-dns-service-types@^1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
-  integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=
-
-multicast-dns@^6.0.1:
-  version "6.2.3"
-  resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229"
-  integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==
+multicast-dns@^7.2.4:
+  version "7.2.4"
+  resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.4.tgz#cf0b115c31e922aeb20b64e6556cbeb34cf0dd19"
+  integrity sha512-XkCYOU+rr2Ft3LI6w4ye51M3VK31qJXFIxu0XLw169PtKG0Zx47OrXeVW/GCYOfpC9s1yyyf1S+L8/4LY0J9Zw==
   dependencies:
-    dns-packet "^1.3.1"
+    dns-packet "^5.2.2"
     thunky "^1.0.2"
 
 mute-stream@~0.0.4:
@@ -5344,15 +5696,10 @@ mute-stream@~0.0.4:
   resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
   integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
 
-nan@^2.13.2:
-  version "2.15.0"
-  resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
-  integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==
-
-nanoid@^3.1.23:
-  version "3.1.25"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152"
-  integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==
+nanoid@^3.3.1:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.2.tgz#c89622fafb4381cd221421c69ec58547a1eec557"
+  integrity sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==
 
 natural-compare@^1.4.0:
   version "1.4.0"
@@ -5364,6 +5711,11 @@ negotiator@0.6.2:
   resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
   integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
 
+negotiator@0.6.3:
+  version "0.6.3"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+  integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
 neo-async@^2.6.2:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
@@ -5379,14 +5731,16 @@ node-fetch-npm@^2.0.2:
     safe-buffer "^5.1.1"
 
 node-fetch@^2.6.1:
-  version "2.6.1"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
-  integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
+  version "2.6.6"
+  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89"
+  integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==
+  dependencies:
+    whatwg-url "^5.0.0"
 
-node-forge@^0.10.0:
-  version "0.10.0"
-  resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
-  integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==
+node-forge@^1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
+  integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
 
 node-gyp@^3.6.2:
   version "3.8.0"
@@ -5423,47 +5777,15 @@ node-gyp@^4.0.0:
     tar "^4.4.8"
     which "1"
 
-node-gyp@^7.1.0:
-  version "7.1.2"
-  resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae"
-  integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==
-  dependencies:
-    env-paths "^2.2.0"
-    glob "^7.1.4"
-    graceful-fs "^4.2.3"
-    nopt "^5.0.0"
-    npmlog "^4.1.2"
-    request "^2.88.2"
-    rimraf "^3.0.2"
-    semver "^7.3.2"
-    tar "^6.0.2"
-    which "^2.0.2"
-
-node-releases@^1.1.75:
-  version "1.1.75"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe"
-  integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==
+node-releases@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
+  integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==
 
-node-sass@^6.0.1:
-  version "6.0.1"
-  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-6.0.1.tgz#cad1ccd0ce63e35c7181f545d8b986f3a9a887fe"
-  integrity sha512-f+Rbqt92Ful9gX0cGtdYwjTrWAaGURgaK5rZCWOgCNyGWusFYHhbqCCBoFBeat+HKETOU02AyTxNhJV0YZf2jQ==
-  dependencies:
-    async-foreach "^0.1.3"
-    chalk "^1.1.1"
-    cross-spawn "^7.0.3"
-    gaze "^1.0.0"
-    get-stdin "^4.0.1"
-    glob "^7.0.3"
-    lodash "^4.17.15"
-    meow "^9.0.0"
-    nan "^2.13.2"
-    node-gyp "^7.1.0"
-    npmlog "^4.0.0"
-    request "^2.88.0"
-    sass-graph "2.2.5"
-    stdout-stream "^1.4.0"
-    "true-case-path" "^1.0.2"
+node-releases@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
+  integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
 
 "nopt@2 || 3":
   version "3.0.6"
@@ -5472,13 +5794,6 @@ node-sass@^6.0.1:
   dependencies:
     abbrev "1"
 
-nopt@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88"
-  integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==
-  dependencies:
-    abbrev "1"
-
 nopt@~4.0.1:
   version "4.0.3"
   resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
@@ -5487,7 +5802,7 @@ nopt@~4.0.1:
     abbrev "1"
     osenv "^0.1.4"
 
-normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0, "normalize-package-data@~1.0.1 || ^2.0.0":
+normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, "normalize-package-data@~1.0.1 || ^2.0.0":
   version "2.5.0"
   resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
   integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -5497,16 +5812,6 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-
     semver "2 || 3 || 4 || 5"
     validate-npm-package-license "^3.0.1"
 
-normalize-package-data@^3.0.0:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e"
-  integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==
-  dependencies:
-    hosted-git-info "^4.0.1"
-    is-core-module "^2.5.0"
-    semver "^7.3.4"
-    validate-npm-package-license "^3.0.1"
-
 normalize-package-data@~2.4.0:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.2.tgz#6b2abd85774e51f7936f1395e45acb905dc849b2"
@@ -5662,6 +5967,13 @@ npm-run-path@^4.0.1:
   dependencies:
     path-key "^3.0.0"
 
+npm-run-path@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00"
+  integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==
+  dependencies:
+    path-key "^4.0.0"
+
 npm-user-validate@~1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/npm-user-validate/-/npm-user-validate-1.0.1.tgz#31428fc5475fe8416023f178c0ab47935ad8c561"
@@ -5780,7 +6092,7 @@ npm@^5.8.0:
     wrappy "~1.0.2"
     write-file-atomic "^2.3.0"
 
-"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@^4.0.0, npmlog@^4.1.2, npmlog@~4.1.2:
+"npmlog@0 || 1 || 2 || 3 || 4", "npmlog@2 || ^3.1.0 || ^4.0.0", npmlog@~4.1.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
   integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
@@ -5806,9 +6118,14 @@ object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
   integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
 
 object-inspect@^1.11.0, object-inspect@^1.9.0:
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
-  integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
+  integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
+
+object-inspect@^1.12.2:
+  version "1.12.2"
+  resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.2.tgz#c0641f26394532f28ab8d796ab954e43c009a8ea"
+  integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==
 
 object-is@^1.0.1:
   version "1.1.5"
@@ -5834,23 +6151,23 @@ object.assign@^4.1.0, object.assign@^4.1.2:
     object-keys "^1.1.1"
 
 object.getownpropertydescriptors@^2.0.3:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7"
-  integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e"
+  integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw==
   dependencies:
     call-bind "^1.0.2"
     define-properties "^1.1.3"
-    es-abstract "^1.18.0-next.2"
+    es-abstract "^1.19.1"
 
 obuf@^1.0.0, obuf@^1.1.2:
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
   integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
 
-on-finished@~2.3.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
-  integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+on-finished@2.4.1:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+  integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
   dependencies:
     ee-first "1.1.1"
 
@@ -5873,10 +6190,17 @@ onetime@^5.1.0, onetime@^5.1.2:
   dependencies:
     mimic-fn "^2.1.0"
 
+onetime@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
+  integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==
+  dependencies:
+    mimic-fn "^4.0.0"
+
 open@^8.0.9:
-  version "8.2.1"
-  resolved "https://registry.yarnpkg.com/open/-/open-8.2.1.tgz#82de42da0ccbf429bc12d099dad2e0975e14e8af"
-  integrity sha512-rXILpcQlkF/QuFez2BJDf3GsqpjGKbkUUToAIGo9A0Q6ZkoSGogZJulrUdwRkrAsoQvoZsrjCYt8+zblOk7JQQ==
+  version "8.4.0"
+  resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8"
+  integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==
   dependencies:
     define-lazy-prop "^2.0.0"
     is-docker "^2.1.1"
@@ -5931,18 +6255,6 @@ osenv@0, osenv@^0.1.4, osenv@^0.1.5:
     os-homedir "^1.0.0"
     os-tmpdir "^1.0.0"
 
-p-defer@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
-  integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
-
-p-event@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5"
-  integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==
-  dependencies:
-    p-timeout "^3.1.0"
-
 p-finally@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@@ -5962,13 +6274,6 @@ p-limit@^2.0.0, p-limit@^2.2.0:
   dependencies:
     p-try "^2.0.0"
 
-p-limit@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
-  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
-  dependencies:
-    yocto-queue "^0.1.0"
-
 p-locate@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
@@ -6010,13 +6315,6 @@ p-retry@^4.5.0:
     "@types/retry" "^0.12.0"
     retry "^0.13.1"
 
-p-timeout@^3.1.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
-  integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
-  dependencies:
-    p-finally "^1.0.0"
-
 p-try@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
@@ -6129,16 +6427,6 @@ parse-json@^4.0.0:
     error-ex "^1.3.1"
     json-parse-better-errors "^1.0.1"
 
-parse-json@^5.0.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
-  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
-  dependencies:
-    "@babel/code-frame" "^7.0.0"
-    error-ex "^1.3.1"
-    json-parse-even-better-errors "^2.3.0"
-    lines-and-columns "^1.1.6"
-
 parseurl@~1.3.2, parseurl@~1.3.3:
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -6174,7 +6462,12 @@ path-key@^3.0.0, path-key@^3.1.0:
   resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
   integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
 
-path-parse@^1.0.6:
+path-key@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
+  integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
+
+path-parse@^1.0.7:
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
@@ -6215,10 +6508,20 @@ performance-now@^2.1.0:
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
   integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
 
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
-  integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pidtree@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c"
+  integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==
 
 pify@^2.0.0:
   version "2.3.0"
@@ -6254,22 +6557,6 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0:
   dependencies:
     find-up "^4.0.0"
 
-please-upgrade-node@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
-  integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==
-  dependencies:
-    semver-compare "^1.0.0"
-
-portfinder@^1.0.28:
-  version "1.0.28"
-  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.28.tgz#67c4622852bd5374dd1dd900f779f53462fac778"
-  integrity sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==
-  dependencies:
-    async "^2.6.2"
-    debug "^3.1.1"
-    mkdirp "^0.5.5"
-
 postcss-modules-extract-imports@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d"
@@ -6299,26 +6586,26 @@ postcss-modules-values@^4.0.0:
     icss-utils "^5.0.0"
 
 postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
-  version "6.0.6"
-  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea"
-  integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==
+  version "6.0.8"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz#f023ed7a9ea736cd7ef70342996e8e78645a7914"
+  integrity sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==
   dependencies:
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
 
-postcss-value-parser@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb"
-  integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==
+postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+  integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
 
-postcss@^8.2.15:
-  version "8.3.6"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea"
-  integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A==
+postcss@^8.4.7:
+  version "8.4.12"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905"
+  integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==
   dependencies:
-    colorette "^1.2.2"
-    nanoid "^3.1.23"
-    source-map-js "^0.6.2"
+    nanoid "^3.3.1"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
 
 prelude-ls@^1.2.1:
   version "1.2.1"
@@ -6347,33 +6634,28 @@ prettier-plugin-import-sort@^0.0.7:
     import-sort-parser-babylon "^6.0.0"
     import-sort-parser-typescript "^6.0.0"
 
-prettier-plugin-organize-imports@^2.2.0:
-  version "2.3.3"
-  resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-2.3.3.tgz#6877bcf8ca02569198d8f419c954a0d90a95de15"
-  integrity sha512-PBOwQ8vEIB2b7B3gCuBG7D+dqsr1fsTR4TSAjNacRVdHJrD0yzgz9grOLPSyfwJm+NUTZLyWeHoZ+1mHaUrk+g==
+prettier-plugin-organize-imports@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.0.0.tgz#39739423cc7069f2a3bfa58d14f8a502ff163df2"
+  integrity sha512-juSCJs5TMOqGGPaN/A/1xzWFzRPH2LG1LPLCr64dzKaVnPafJdtgDNmDVlU+8A4LbQzVJg0DTvgA8swBuIUhlg==
 
-prettier-plugin-packagejson@^2.2.11:
-  version "2.2.11"
-  resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.2.11.tgz#640b6301da3a58c489889b3d315255e18153daf0"
-  integrity sha512-oJCBCEkHIKScEv6qNQC47S39NXlevbzwvoJE3gflmBB8/3BEsC6ZRi+hwFVajw32b4tDI9hFXPIzmVd/T8Rm9w==
+prettier-plugin-packagejson@^2.2.18:
+  version "2.2.18"
+  resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.2.18.tgz#c5dc50208d7328b10011daea775fd358d43cab1b"
+  integrity sha512-iBjQ3IY6IayFrQHhXvg+YvKprPUUiIJ04Vr9+EbeQPfwGajznArIqrN33c5bi4JcIvmLHGROIMOm9aYakJj/CA==
   dependencies:
-    sort-package-json "1.50.0"
+    sort-package-json "1.57.0"
 
-prettier@^2.3.2:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
-  integrity sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==
+prettier@^2.7.1:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
+  integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
 
 process-nextick-args@~2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
   integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
 
-progress@^2.0.0:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
-  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
-
 promise-inflight@^1.0.1, promise-inflight@~1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
@@ -6406,7 +6688,7 @@ protoduck@^5.0.0:
   dependencies:
     genfun "^5.0.0"
 
-proxy-addr@~2.0.5:
+proxy-addr@~2.0.7:
   version "2.0.7"
   resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
   integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
@@ -6462,11 +6744,6 @@ pumpify@^1.3.3:
     inherits "^2.0.3"
     pump "^2.0.0"
 
-punycode@1.3.2:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
-  integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
-
 punycode@^2.1.0, punycode@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@@ -6477,15 +6754,17 @@ qrcode-terminal@^0.12.0:
   resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819"
   integrity sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==
 
-qs@6.7.0:
-  version "6.7.0"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
-  integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+qs@6.10.3:
+  version "6.10.3"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e"
+  integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==
+  dependencies:
+    side-channel "^1.0.4"
 
 qs@~6.5.2:
-  version "6.5.2"
-  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
-  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+  version "6.5.3"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
+  integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
 
 query-string@^6.1.0:
   version "6.14.1"
@@ -6497,25 +6776,15 @@ query-string@^6.1.0:
     split-on-first "^1.0.0"
     strict-uri-encode "^2.0.0"
 
-querystring@0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
-  integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
-
 queue-microtask@^1.2.2:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
   integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
 
-quick-lru@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
-  integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
-
 qw@~1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4"
-  integrity sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.2.tgz#0c31a6f810320a91c58b05198679427103b03c4a"
+  integrity sha512-1PhZ/iLKwlVNq45dnerTMKFjMof49uqli7/0QsvPNbX5OJ3IZ8msa9lUpvPheVdP+IYYPrf6cOaVil7S35joVA==
 
 randombytes@^2.1.0:
   version "2.1.0"
@@ -6529,13 +6798,13 @@ range-parser@^1.2.1, range-parser@~1.2.1:
   resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
   integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
 
-raw-body@2.4.0:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
-  integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+raw-body@2.5.1:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857"
+  integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==
   dependencies:
-    bytes "3.1.0"
-    http-errors "1.7.2"
+    bytes "3.1.2"
+    http-errors "2.0.0"
     iconv-lite "0.4.24"
     unpipe "1.0.0"
 
@@ -6597,15 +6866,6 @@ read-pkg-up@^2.0.0:
     find-up "^2.0.0"
     read-pkg "^2.0.0"
 
-read-pkg-up@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
-  integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
-  dependencies:
-    find-up "^4.1.0"
-    read-pkg "^5.2.0"
-    type-fest "^0.8.1"
-
 read-pkg@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
@@ -6615,16 +6875,6 @@ read-pkg@^2.0.0:
     normalize-package-data "^2.3.2"
     path-type "^2.0.0"
 
-read-pkg@^5.2.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
-  integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
-  dependencies:
-    "@types/normalize-package-data" "^2.4.0"
-    normalize-package-data "^2.5.0"
-    parse-json "^5.0.0"
-    type-fest "^0.6.0"
-
 read@1, read@~1.0.1, read@~1.0.7:
   version "1.0.7"
   resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
@@ -6688,34 +6938,33 @@ rechoir@^0.7.0:
   dependencies:
     resolve "^1.9.0"
 
-reconnecting-websocket@^4.4.0:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
-  integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
-
-redent@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
-  integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
+redux@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.2.tgz#140f35426d99bb4729af760afcf79eaaac407104"
+  integrity sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==
   dependencies:
-    indent-string "^4.0.0"
-    strip-indent "^3.0.0"
+    "@babel/runtime" "^7.9.2"
 
-redux@^4.0.4:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/redux/-/redux-4.1.1.tgz#76f1c439bb42043f985fbd9bf21990e60bd67f47"
-  integrity sha512-hZQZdDEM25UY2P493kPYuKqviVwZ58lEmGQNeQ+gXa+U0gYPUBf7NKYazbe3m+bs/DzM/ahN12DbF+NG8i0CWw==
+reflect-metadata@^0.1.13:
+  version "0.1.13"
+  resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
+  integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
+
+regenerate-unicode-properties@^10.0.1:
+  version "10.0.1"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56"
+  integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==
   dependencies:
-    "@babel/runtime" "^7.9.2"
+    regenerate "^1.4.2"
 
-regenerate-unicode-properties@^8.2.0:
-  version "8.2.0"
-  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
-  integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==
+regenerate-unicode-properties@^9.0.0:
+  version "9.0.0"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326"
+  integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==
   dependencies:
-    regenerate "^1.4.0"
+    regenerate "^1.4.2"
 
-regenerate@^1.4.0:
+regenerate@^1.4.2:
   version "1.4.2"
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
   integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
@@ -6725,10 +6974,10 @@ regenerator-runtime@^0.13.4:
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
   integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
 
-regenerator-transform@^0.14.2:
-  version "0.14.5"
-  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
-  integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==
+regenerator-transform@^0.15.0:
+  version "0.15.0"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.0.tgz#cbd9ead5d77fae1a48d957cf889ad0586adb6537"
+  integrity sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==
   dependencies:
     "@babel/runtime" "^7.8.4"
 
@@ -6740,22 +6989,34 @@ regexp.prototype.flags@^1.2.0:
     call-bind "^1.0.2"
     define-properties "^1.1.3"
 
-regexpp@^3.1.0:
+regexpp@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2"
   integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==
 
 regexpu-core@^4.7.1:
-  version "4.7.1"
-  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6"
-  integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==
+  version "4.8.0"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0"
+  integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==
+  dependencies:
+    regenerate "^1.4.2"
+    regenerate-unicode-properties "^9.0.0"
+    regjsgen "^0.5.2"
+    regjsparser "^0.7.0"
+    unicode-match-property-ecmascript "^2.0.0"
+    unicode-match-property-value-ecmascript "^2.0.0"
+
+regexpu-core@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.1.0.tgz#2f8504c3fd0ebe11215783a41541e21c79942c6d"
+  integrity sha512-bb6hk+xWd2PEOkj5It46A16zFMs2mv86Iwpdu94la4S3sJ7C973h2dHpYKwIBGaWSO7cIRJ+UX0IeMaWcO4qwA==
   dependencies:
-    regenerate "^1.4.0"
-    regenerate-unicode-properties "^8.2.0"
-    regjsgen "^0.5.1"
-    regjsparser "^0.6.4"
-    unicode-match-property-ecmascript "^1.0.4"
-    unicode-match-property-value-ecmascript "^1.2.0"
+    regenerate "^1.4.2"
+    regenerate-unicode-properties "^10.0.1"
+    regjsgen "^0.6.0"
+    regjsparser "^0.8.2"
+    unicode-match-property-ecmascript "^2.0.0"
+    unicode-match-property-value-ecmascript "^2.0.0"
 
 register-service-worker@^1.7.2:
   version "1.7.2"
@@ -6777,19 +7038,31 @@ registry-url@^3.0.3:
   dependencies:
     rc "^1.0.1"
 
-regjsgen@^0.5.1:
+regjsgen@^0.5.2:
   version "0.5.2"
   resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733"
   integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==
 
-regjsparser@^0.6.4:
-  version "0.6.9"
-  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.9.tgz#b489eef7c9a2ce43727627011429cf833a7183e6"
-  integrity sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==
+regjsgen@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d"
+  integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==
+
+regjsparser@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968"
+  integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==
+  dependencies:
+    jsesc "~0.5.0"
+
+regjsparser@^0.8.2:
+  version "0.8.4"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f"
+  integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==
   dependencies:
     jsesc "~0.5.0"
 
-request@^2.74.0, request@^2.85.0, request@^2.87.0, request@^2.88.0, request@^2.88.2:
+request@^2.74.0, request@^2.85.0, request@^2.87.0:
   version "2.88.2"
   resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
   integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
@@ -6868,12 +7141,13 @@ resolve-pathname@^3.0.0:
   integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
 
 resolve@^1.10.0, resolve@^1.14.2, resolve@^1.8.1, resolve@^1.9.0:
-  version "1.20.0"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
-  integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
+  version "1.21.0"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f"
+  integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==
   dependencies:
-    is-core-module "^2.2.0"
-    path-parse "^1.0.6"
+    is-core-module "^2.8.0"
+    path-parse "^1.0.7"
+    supports-preserve-symlinks-flag "^1.0.0"
 
 restore-cursor@^3.1.0:
   version "3.1.0"
@@ -6903,6 +7177,11 @@ reusify@^1.0.4:
   resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
   integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
 
+rfdc@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
+  integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
+
 rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3:
   version "2.7.1"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
@@ -6943,26 +7222,26 @@ run-queue@^1.0.0, run-queue@^1.0.3:
   dependencies:
     aproba "^1.1.1"
 
-rxjs@^6.6.7:
-  version "6.6.7"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
-  integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
+rxjs@^7.5.5:
+  version "7.5.5"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f"
+  integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw==
   dependencies:
-    tslib "^1.9.0"
+    tslib "^2.1.0"
 
-rxjs@^7.2.0:
-  version "7.3.0"
-  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.3.0.tgz#39fe4f3461dc1e50be1475b2b85a0a88c1e938c6"
-  integrity sha512-p2yuGIg9S1epc3vrjKf6iVb3RCaAYjYskkO+jHIaV0IjOPlJop4UnodOoFb2xeNwlguqLYvGw1b1McillYb5Gw==
+rxjs@^7.5.6:
+  version "7.5.6"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc"
+  integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==
   dependencies:
-    tslib "~2.1.0"
+    tslib "^2.1.0"
 
 safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
   integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
 
-safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
+safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
   integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -6972,24 +7251,23 @@ safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1,
   resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
   integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
 
-sass-graph@2.2.5:
-  version "2.2.5"
-  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.5.tgz#a981c87446b8319d96dce0671e487879bd24c2e8"
-  integrity sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==
-  dependencies:
-    glob "^7.0.0"
-    lodash "^4.0.0"
-    scss-tokenizer "^0.2.3"
-    yargs "^13.3.2"
-
-sass-loader@^12.1.0:
-  version "12.1.0"
-  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.1.0.tgz#b73324622231009da6fba61ab76013256380d201"
-  integrity sha512-FVJZ9kxVRYNZTIe2xhw93n3xJNYZADr+q69/s98l9nTCrWASo+DR2Ot0s5xTKQDDEosUkatsGeHxcH4QBp5bSg==
+sass-loader@^13.0.2:
+  version "13.0.2"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-13.0.2.tgz#e81a909048e06520e9f2ff25113a801065adb3fe"
+  integrity sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==
   dependencies:
     klona "^2.0.4"
     neo-async "^2.6.2"
 
+sass@^1.54.0:
+  version "1.54.0"
+  resolved "https://registry.yarnpkg.com/sass/-/sass-1.54.0.tgz#24873673265e2a4fe3d3a997f714971db2fba1f4"
+  integrity sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==
+  dependencies:
+    chokidar ">=3.0.0 <4.0.0"
+    immutable "^4.0.0"
+    source-map-js ">=0.6.2 <2.0.0"
+
 schema-utils@^2.6.5:
   version "2.7.1"
   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
@@ -6999,7 +7277,7 @@ schema-utils@^2.6.5:
     ajv "^6.12.4"
     ajv-keywords "^3.5.2"
 
-schema-utils@^3.0.0, schema-utils@^3.1.0:
+schema-utils@^3.1.0, schema-utils@^3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281"
   integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
@@ -7008,30 +7286,27 @@ schema-utils@^3.0.0, schema-utils@^3.1.0:
     ajv "^6.12.5"
     ajv-keywords "^3.5.2"
 
-scss-tokenizer@^0.2.3:
-  version "0.2.3"
-  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
-  integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE=
+schema-utils@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.0.0.tgz#60331e9e3ae78ec5d16353c467c34b3a0a1d3df7"
+  integrity sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==
   dependencies:
-    js-base64 "^2.1.8"
-    source-map "^0.4.2"
+    "@types/json-schema" "^7.0.9"
+    ajv "^8.8.0"
+    ajv-formats "^2.1.1"
+    ajv-keywords "^5.0.0"
 
 select-hose@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
   integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
 
-selfsigned@^1.10.11:
-  version "1.10.11"
-  resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9"
-  integrity sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA==
+selfsigned@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.0.1.tgz#8b2df7fa56bf014d19b6007655fff209c0ef0a56"
+  integrity sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==
   dependencies:
-    node-forge "^0.10.0"
-
-semver-compare@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
-  integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w=
+    node-forge "^1"
 
 semver-diff@^2.0.0:
   version "2.1.0"
@@ -7055,36 +7330,43 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
   resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
   integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
 
-semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5:
+semver@^7.3.5:
   version "7.3.5"
   resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
   integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
   dependencies:
     lru-cache "^6.0.0"
 
+semver@^7.3.7:
+  version "7.3.7"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
+  integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
+  dependencies:
+    lru-cache "^6.0.0"
+
 semver@~5.3.0:
   version "5.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
   integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
 
-send@0.17.1:
-  version "0.17.1"
-  resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
-  integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+send@0.18.0:
+  version "0.18.0"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
+  integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
   dependencies:
     debug "2.6.9"
-    depd "~1.1.2"
-    destroy "~1.0.4"
+    depd "2.0.0"
+    destroy "1.2.0"
     encodeurl "~1.0.2"
     escape-html "~1.0.3"
     etag "~1.8.1"
     fresh "0.5.2"
-    http-errors "~1.7.2"
+    http-errors "2.0.0"
     mime "1.6.0"
-    ms "2.1.1"
-    on-finished "~2.3.0"
+    ms "2.1.3"
+    on-finished "2.4.1"
     range-parser "~1.2.1"
-    statuses "~1.5.0"
+    statuses "2.0.1"
 
 serialize-javascript@^6.0.0:
   version "6.0.0"
@@ -7106,15 +7388,15 @@ serve-index@^1.9.1:
     mime-types "~2.1.17"
     parseurl "~1.3.2"
 
-serve-static@1.14.1:
-  version "1.14.1"
-  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
-  integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+serve-static@1.15.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
+  integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
   dependencies:
     encodeurl "~1.0.2"
     escape-html "~1.0.3"
     parseurl "~1.3.3"
-    send "0.17.1"
+    send "0.18.0"
 
 set-blocking@^2.0.0, set-blocking@~2.0.0:
   version "2.0.0"
@@ -7126,10 +7408,10 @@ setprototypeof@1.1.0:
   resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
   integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
 
-setprototypeof@1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
-  integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+setprototypeof@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+  integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
 
 sha@~2.0.1:
   version "2.0.1"
@@ -7185,15 +7467,25 @@ side-channel@^1.0.4:
     object-inspect "^1.9.0"
 
 signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
-  integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af"
+  integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==
+
+signal-exit@^3.0.7:
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+  integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
 
 slash@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
   integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
 
+slash@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
+  integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
+
 slice-ansi@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787"
@@ -7212,6 +7504,14 @@ slice-ansi@^4.0.0:
     astral-regex "^2.0.0"
     is-fullwidth-code-point "^3.0.0"
 
+slice-ansi@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a"
+  integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==
+  dependencies:
+    ansi-styles "^6.0.0"
+    is-fullwidth-code-point "^4.0.0"
+
 slide@^1.1.3, slide@^1.1.6, slide@~1.1.3, slide@~1.1.6:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707"
@@ -7227,13 +7527,13 @@ smart-buffer@^4.1.0:
   resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
   integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==
 
-sockjs@^0.3.21:
-  version "0.3.21"
-  resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.21.tgz#b34ffb98e796930b60a0cfa11904d6a339a7d417"
-  integrity sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==
+sockjs@^0.3.24:
+  version "0.3.24"
+  resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce"
+  integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==
   dependencies:
     faye-websocket "^0.11.3"
-    uuid "^3.4.0"
+    uuid "^8.3.2"
     websocket-driver "^0.7.4"
 
 socks-proxy-agent@^3.0.1:
@@ -7273,10 +7573,10 @@ sort-object-keys@^1.1.3:
   resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
   integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
 
-sort-package-json@1.50.0:
-  version "1.50.0"
-  resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.50.0.tgz#19fc109fe23bd157bd03c8e572fa3251a52467d8"
-  integrity sha512-qZpqhMU9XTntebgAgc4hv/D6Fzhh7kFnwvV6a7+q8y8J5JoaDqPYQnvXPf7BBqG95tdE8X6JVNo7/jDzcbdfUg==
+sort-package-json@1.57.0:
+  version "1.57.0"
+  resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.57.0.tgz#e95fb44af8ede0bb6147e3f39258102d4bb23fc4"
+  integrity sha512-FYsjYn2dHTRb41wqnv+uEqCUvBpK3jZcTp9rbz2qDTmel7Pmdtf+i2rLaaPMRZeSVM60V3Se31GyWFpmKs4Q5Q==
   dependencies:
     detect-indent "^6.0.0"
     detect-newline "3.1.0"
@@ -7298,31 +7598,29 @@ sorted-union-stream@~2.1.3:
     from2 "^1.3.0"
     stream-iterate "^1.1.0"
 
-sortpack@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/sortpack/-/sortpack-2.2.0.tgz#8f5ffc34a62305201186dae05658ef36723cc50d"
-  integrity sha512-2W/CtgiUebcL2znZheuNX2TQ0Z1XioF3yw6rzyvTYTJirYVjNbYjV4BJ62OvPAytF9pnnDI6bs07i1b/uK7qOQ==
+sortpack@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/sortpack/-/sortpack-2.3.0.tgz#90d4688e61a91fa1da61e1b0f04dab327b94a3e8"
+  integrity sha512-BkqYsA2ksQkVlk2xrwEZoWaz8y26ZMLEkrgdUjrkU5GDysCBoFmDt76D+P8hfJsu9AGdsqqK8XrEpH37ZjG7yw==
 
-source-map-js@^0.6.2:
-  version "0.6.2"
-  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
-  integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
+"source-map-js@>=0.6.2 <2.0.0":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf"
+  integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==
+
+source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
 
-source-map-support@~0.5.19:
-  version "0.5.19"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
-  integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
+source-map-support@~0.5.20:
+  version "0.5.21"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+  integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
   dependencies:
     buffer-from "^1.0.0"
     source-map "^0.6.0"
 
-source-map@^0.4.2:
-  version "0.4.4"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
-  integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
-  dependencies:
-    amdefine ">=0.0.4"
-
 source-map@^0.5.0:
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -7360,9 +7658,9 @@ spdx-expression-parse@^3.0.0:
     spdx-license-ids "^3.0.0"
 
 spdx-license-ids@^3.0.0:
-  version "3.0.10"
-  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz#0d9becccde7003d6c658d487dd48a32f0bf3014b"
-  integrity sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==
+  version "3.0.11"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95"
+  integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==
 
 spdy-transport@^3.0.0:
   version "3.0.0"
@@ -7398,9 +7696,9 @@ sprintf-js@~1.0.2:
   integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
 
 sshpk@^1.7.0:
-  version "1.16.1"
-  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
-  integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
+  version "1.17.0"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5"
+  integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==
   dependencies:
     asn1 "~0.2.3"
     assert-plus "^1.0.0"
@@ -7426,18 +7724,16 @@ ssri@^6.0.0, ssri@^6.0.1:
   dependencies:
     figgy-pudding "^3.5.1"
 
-"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+statuses@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+  integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+"statuses@>= 1.4.0 < 2":
   version "1.5.0"
   resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
   integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
 
-stdout-stream@^1.4.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
-  integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==
-  dependencies:
-    readable-stream "^2.0.1"
-
 stream-each@^1.1.0:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
@@ -7464,7 +7760,7 @@ strict-uri-encode@^2.0.0:
   resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
   integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
 
-string-argv@0.3.1:
+string-argv@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
   integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==
@@ -7478,7 +7774,16 @@ string-width@^1.0.1:
     is-fullwidth-code-point "^1.0.0"
     strip-ansi "^3.0.0"
 
-"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1:
+"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0:
+  version "4.2.3"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+  integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+  dependencies:
+    emoji-regex "^8.0.0"
+    is-fullwidth-code-point "^3.0.0"
+    strip-ansi "^6.0.1"
+
+string-width@^2.0.0, string-width@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
   integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
@@ -7495,14 +7800,14 @@ string-width@^3.0.0, string-width@^3.1.0:
     is-fullwidth-code-point "^2.0.0"
     strip-ansi "^5.1.0"
 
-string-width@^4.1.0, string-width@^4.2.0:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5"
-  integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==
+string-width@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.0.tgz#5ab00980cfb29f43e736b113a120a73a0fb569d3"
+  integrity sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==
   dependencies:
-    emoji-regex "^8.0.0"
-    is-fullwidth-code-point "^3.0.0"
-    strip-ansi "^6.0.0"
+    eastasianwidth "^0.2.0"
+    emoji-regex "^9.2.2"
+    strip-ansi "^7.0.1"
 
 string.prototype.trimend@^1.0.4:
   version "1.0.4"
@@ -7539,15 +7844,6 @@ string_decoder@~1.1.1:
   dependencies:
     safe-buffer "~5.1.0"
 
-stringify-object@^3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
-  integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
-  dependencies:
-    get-own-enumerable-property-symbols "^3.0.0"
-    is-obj "^1.0.1"
-    is-regexp "^1.0.0"
-
 strip-ansi@^3.0.0, strip-ansi@^3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
@@ -7569,19 +7865,19 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
   dependencies:
     ansi-regex "^4.1.0"
 
-strip-ansi@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
-  integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
   dependencies:
-    ansi-regex "^5.0.0"
+    ansi-regex "^5.0.1"
 
-strip-ansi@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.0.tgz#1dc49b980c3a4100366617adac59327eefdefcb0"
-  integrity sha512-UhDTSnGF1dc0DRbUqr1aXwNoY3RgVkSWG8BrpnuFIxhP57IqbS7IRta2Gfiavds4yCxc5+fEAVVOgBZWnYkvzg==
+strip-ansi@^7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
+  integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==
   dependencies:
-    ansi-regex "^6.0.0"
+    ansi-regex "^6.0.1"
 
 strip-bom@^3.0.0:
   version "3.0.0"
@@ -7598,12 +7894,10 @@ strip-final-newline@^2.0.0:
   resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
   integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
 
-strip-indent@^3.0.0:
+strip-final-newline@^3.0.0:
   version "3.0.0"
-  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
-  integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
-  dependencies:
-    min-indent "^1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
+  integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
 
 strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
   version "3.1.1"
@@ -7615,15 +7909,10 @@ strip-json-comments@~2.0.1:
   resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
   integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
 
-style-loader@^3.1.0:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.2.1.tgz#63cb920ec145c8669e9a50e92961452a1ef5dcde"
-  integrity sha512-1k9ZosJCRFaRbY6hH49JFlRB0fVSbmnyq1iTPjNxUmGVjBNEmwrrHPenhlp+Lgo51BojHSf6pl2FcqYaN3PfVg==
-
-supports-color@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
-  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+style-loader@^3.3.1:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.1.tgz#057dfa6b3d4d7c7064462830f9113ed417d38575"
+  integrity sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==
 
 supports-color@^5.3.0:
   version "5.5.0"
@@ -7646,22 +7935,15 @@ supports-color@^8.0.0:
   dependencies:
     has-flag "^4.0.0"
 
-table@^6.0.9:
-  version "6.7.1"
-  resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2"
-  integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==
-  dependencies:
-    ajv "^8.0.1"
-    lodash.clonedeep "^4.5.0"
-    lodash.truncate "^4.4.2"
-    slice-ansi "^4.0.0"
-    string-width "^4.2.0"
-    strip-ansi "^6.0.0"
+supports-preserve-symlinks-flag@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
 
 tapable@^2.1.1, tapable@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
-  integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+  integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
 
 tar@^2.0.0:
   version "2.2.2"
@@ -7685,18 +7967,6 @@ tar@^4.4.0, tar@^4.4.2, tar@^4.4.3, tar@^4.4.8:
     safe-buffer "^5.2.1"
     yallist "^3.1.1"
 
-tar@^6.0.2:
-  version "6.1.10"
-  resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.10.tgz#8a320a74475fba54398fa136cd9883aa8ad11175"
-  integrity sha512-kvvfiVvjGMxeUNB6MyYv5z7vhfFRwbwCXJAeL0/lnbrttBVqcMOnpHUf0X42LrPMR8mMpgapkJMchFH4FSHzNA==
-  dependencies:
-    chownr "^2.0.0"
-    fs-minipass "^2.0.0"
-    minipass "^3.0.0"
-    minizlib "^2.1.1"
-    mkdirp "^1.0.3"
-    yallist "^4.0.0"
-
 term-size@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
@@ -7705,25 +7975,34 @@ term-size@^1.2.0:
     execa "^0.7.0"
 
 terser-webpack-plugin@^5.1.3:
-  version "5.1.4"
-  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.4.tgz#c369cf8a47aa9922bd0d8a94fe3d3da11a7678a1"
-  integrity sha512-C2WkFwstHDhVEmsmlCxrXUtVklS+Ir1A7twrYzrDrQQOIMOaVAYykaoo/Aq1K0QRkMoY2hhvDQY1cm4jnIMFwA==
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz#21641326486ecf91d8054161c816e464435bae9f"
+  integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==
   dependencies:
-    jest-worker "^27.0.2"
-    p-limit "^3.1.0"
-    schema-utils "^3.0.0"
+    jest-worker "^27.4.1"
+    schema-utils "^3.1.1"
     serialize-javascript "^6.0.0"
     source-map "^0.6.1"
-    terser "^5.7.0"
+    terser "^5.7.2"
 
-terser@^5.7.0, terser@^5.7.1:
-  version "5.7.1"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784"
-  integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==
+terser@^5.14.2:
+  version "5.14.2"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
+  integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
+  dependencies:
+    "@jridgewell/source-map" "^0.3.2"
+    acorn "^8.5.0"
+    commander "^2.20.0"
+    source-map-support "~0.5.20"
+
+terser@^5.7.2:
+  version "5.10.0"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-5.10.0.tgz#b86390809c0389105eb0a0b62397563096ddafcc"
+  integrity sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==
   dependencies:
     commander "^2.20.0"
     source-map "~0.7.2"
-    source-map-support "~0.5.19"
+    source-map-support "~0.5.20"
 
 text-table@^0.2.0, text-table@~0.2.0:
   version "0.2.0"
@@ -7754,9 +8033,9 @@ timed-out@^4.0.0:
   integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
 
 tiny-invariant@^1.0.2:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
-  integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9"
+  integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==
 
 tiny-relative-date@^1.3.0:
   version "1.3.0"
@@ -7768,12 +8047,12 @@ tiny-warning@^1.0.0:
   resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
   integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
 
-tippy.js@^6.3.1:
-  version "6.3.1"
-  resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.1.tgz#3788a007be7015eee0fd589a66b98fb3f8f10181"
-  integrity sha512-JnFncCq+rF1dTURupoJ4yPie5Cof978inW6/4S6kmWV7LL9YOSEVMifED3KdrVPEG+Z/TFH2CDNJcQEfaeuQww==
+tippy.js@^6.3.7:
+  version "6.3.7"
+  resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c"
+  integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==
   dependencies:
-    "@popperjs/core" "^2.8.3"
+    "@popperjs/core" "^2.9.0"
 
 to-fast-properties@^2.0.0:
   version "2.0.0"
@@ -7787,15 +8066,15 @@ to-regex-range@^5.0.1:
   dependencies:
     is-number "^7.0.0"
 
-toastify-js@^1.11.1:
-  version "1.11.1"
-  resolved "https://registry.yarnpkg.com/toastify-js/-/toastify-js-1.11.1.tgz#023a4ce64ecdead1d6d170072b62bd345088c427"
-  integrity sha512-O1UR06KEhFY9Vu2iKltgOE62+Vq/5iU7AOktouFkEegEisrqtNhEri9RpSd6u6wyPsd4Ae9RT1io3uwkMAlLVQ==
+toastify-js@^1.12.0:
+  version "1.12.0"
+  resolved "https://registry.yarnpkg.com/toastify-js/-/toastify-js-1.12.0.tgz#cc1c4f5c7e7380e854e20bedceb51980ea29f64d"
+  integrity sha512-HeMHCO9yLPvP9k0apGSdPUWrUbLnxUKNFzgUoZp1PHCLploIX/4DSQ7V8H25ef+h4iO9n0he7ImfcndnN6nDrQ==
 
-toidentifier@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
-  integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+toidentifier@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+  integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
 
 tough-cookie@~2.5.0:
   version "2.5.0"
@@ -7805,32 +8084,25 @@ tough-cookie@~2.5.0:
     psl "^1.1.28"
     punycode "^2.1.1"
 
+tr46@~0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+  integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=
+
 tributejs@^5.1.3:
   version "5.1.3"
   resolved "https://registry.yarnpkg.com/tributejs/-/tributejs-5.1.3.tgz#980600fc72865be5868893078b4bfde721129eae"
   integrity sha512-B5CXihaVzXw+1UHhNFyAwUTMDk1EfoLP5Tj1VhD9yybZ1I8DZJEv8tZ1l0RJo0t0tk9ZhR8eG5tEsaCvRigmdQ==
 
-trim-newlines@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
-  integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
-
-"true-case-path@^1.0.2":
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
-  integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==
-  dependencies:
-    glob "^7.1.2"
-
-tslib@^1.8.1, tslib@^1.9.0:
+tslib@^1.8.1:
   version "1.14.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
-tslib@~2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
-  integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
+tslib@^2.1.0:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
+  integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
 
 tsutils@^3.21.0:
   version "3.21.0"
@@ -7858,11 +8130,6 @@ type-check@^0.4.0, type-check@~0.4.0:
   dependencies:
     prelude-ls "^1.2.1"
 
-type-fest@^0.18.0:
-  version "0.18.1"
-  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f"
-  integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==
-
 type-fest@^0.20.2:
   version "0.20.2"
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
@@ -7873,17 +8140,7 @@ type-fest@^0.21.3:
   resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
   integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
 
-type-fest@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
-  integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
-
-type-fest@^0.8.1:
-  version "0.8.1"
-  resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
-  integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
-
-type-is@~1.6.17, type-is@~1.6.18:
+type-is@~1.6.18:
   version "1.6.18"
   resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
   integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
@@ -7901,10 +8158,10 @@ typescript@^3.2.4:
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
   integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
 
-typescript@^4.3.5:
-  version "4.3.5"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"
-  integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==
+typescript@^4.7.4:
+  version "4.7.4"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
+  integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
 
 uc.micro@^1.0.1, uc.micro@^1.0.5:
   version "1.0.6"
@@ -7931,28 +8188,28 @@ unbox-primitive@^1.0.1:
     has-symbols "^1.0.2"
     which-boxed-primitive "^1.0.2"
 
-unicode-canonical-property-names-ecmascript@^1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
-  integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
+unicode-canonical-property-names-ecmascript@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc"
+  integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==
 
-unicode-match-property-ecmascript@^1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
-  integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
+unicode-match-property-ecmascript@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3"
+  integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==
   dependencies:
-    unicode-canonical-property-names-ecmascript "^1.0.4"
-    unicode-property-aliases-ecmascript "^1.0.4"
+    unicode-canonical-property-names-ecmascript "^2.0.0"
+    unicode-property-aliases-ecmascript "^2.0.0"
 
-unicode-match-property-value-ecmascript@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531"
-  integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==
+unicode-match-property-value-ecmascript@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714"
+  integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==
 
-unicode-property-aliases-ecmascript@^1.0.4:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4"
-  integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==
+unicode-property-aliases-ecmascript@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8"
+  integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==
 
 unique-filename@^1.1.0, unique-filename@^1.1.1, unique-filename@~1.1.0:
   version "1.1.1"
@@ -7985,6 +8242,14 @@ unzip-response@^2.0.1:
   resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
   integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
 
+update-browserslist-db@^1.0.5:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
+  integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
+  dependencies:
+    escalade "^3.1.1"
+    picocolors "^1.0.0"
+
 update-notifier@^2.2.0, update-notifier@^2.3.0, update-notifier@^2.5.0:
   version "2.5.0"
   resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
@@ -8015,14 +8280,6 @@ url-parse-lax@^1.0.0:
   dependencies:
     prepend-http "^1.0.1"
 
-url@^0.11.0:
-  version "0.11.0"
-  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
-  integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=
-  dependencies:
-    punycode "1.3.2"
-    querystring "0.2.0"
-
 util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -8045,12 +8302,17 @@ utils-merge@1.0.1:
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
   integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
 
-uuid@^3.2.1, uuid@^3.3.2, uuid@^3.4.0:
+uuid@^3.2.1, uuid@^3.3.2:
   version "3.4.0"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
   integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
 
-v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0:
+uuid@^8.3.2:
+  version "8.3.2"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+  integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+v8-compile-cache@^2.0.3:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
   integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
@@ -8094,10 +8356,10 @@ void-elements@^2.0.1:
   resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
   integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
 
-watchpack@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.2.0.tgz#47d78f5415fe550ecd740f99fe2882323a58b1ce"
-  integrity sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==
+watchpack@^2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
+  integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
   dependencies:
     glob-to-regexp "^0.4.1"
     graceful-fs "^4.1.2"
@@ -8116,67 +8378,74 @@ wcwidth@^1.0.0:
   dependencies:
     defaults "^1.0.3"
 
-webpack-cli@^4.7.2:
-  version "4.8.0"
-  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.8.0.tgz#5fc3c8b9401d3c8a43e2afceacfa8261962338d1"
-  integrity sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==
+webidl-conversions@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+  integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=
+
+webpack-cli@^4.10.0:
+  version "4.10.0"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31"
+  integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==
   dependencies:
     "@discoveryjs/json-ext" "^0.5.0"
-    "@webpack-cli/configtest" "^1.0.4"
-    "@webpack-cli/info" "^1.3.0"
-    "@webpack-cli/serve" "^1.5.2"
-    colorette "^1.2.1"
+    "@webpack-cli/configtest" "^1.2.0"
+    "@webpack-cli/info" "^1.5.0"
+    "@webpack-cli/serve" "^1.7.0"
+    colorette "^2.0.14"
     commander "^7.0.0"
-    execa "^5.0.0"
+    cross-spawn "^7.0.3"
     fastest-levenshtein "^1.0.12"
     import-local "^3.0.2"
     interpret "^2.2.0"
     rechoir "^0.7.0"
-    v8-compile-cache "^2.2.0"
     webpack-merge "^5.7.3"
 
-webpack-dev-middleware@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.0.0.tgz#0abe825275720e0a339978aea5f0b03b140c1584"
-  integrity sha512-9zng2Z60pm6A98YoRcA0wSxw1EYn7B7y5owX/Tckyt9KGyULTkLtiavjaXlWqOMkM0YtqGgL3PvMOFgyFLq8vw==
+webpack-dev-middleware@^5.3.1:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz#aa079a8dedd7e58bfeab358a9af7dab304cee57f"
+  integrity sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==
   dependencies:
-    colorette "^1.2.2"
-    mem "^8.1.1"
-    memfs "^3.2.2"
+    colorette "^2.0.10"
+    memfs "^3.4.1"
     mime-types "^2.1.31"
     range-parser "^1.2.1"
-    schema-utils "^3.0.0"
-
-webpack-dev-server@4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.0.0.tgz#fb4906e91182154bba54a66e6e06f84c1e3c0a80"
-  integrity sha512-ya5cjoBSf3LqrshZn2HMaRZQx8YRNBE+tx+CQNFGaLLHrvs4Y1aik0sl5SFhLz2cW1O9/NtyaZhthc+8UiuvkQ==
-  dependencies:
-    ansi-html "^0.0.7"
-    bonjour "^3.5.0"
-    chokidar "^3.5.1"
-    colorette "^1.2.2"
+    schema-utils "^4.0.0"
+
+webpack-dev-server@4.9.3:
+  version "4.9.3"
+  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.9.3.tgz#2360a5d6d532acb5410a668417ad549ee3b8a3c9"
+  integrity sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==
+  dependencies:
+    "@types/bonjour" "^3.5.9"
+    "@types/connect-history-api-fallback" "^1.3.5"
+    "@types/express" "^4.17.13"
+    "@types/serve-index" "^1.9.1"
+    "@types/serve-static" "^1.13.10"
+    "@types/sockjs" "^0.3.33"
+    "@types/ws" "^8.5.1"
+    ansi-html-community "^0.0.8"
+    bonjour-service "^1.0.11"
+    chokidar "^3.5.3"
+    colorette "^2.0.10"
     compression "^1.7.4"
-    connect-history-api-fallback "^1.6.0"
-    del "^6.0.0"
-    express "^4.17.1"
+    connect-history-api-fallback "^2.0.0"
+    default-gateway "^6.0.3"
+    express "^4.17.3"
     graceful-fs "^4.2.6"
     html-entities "^2.3.2"
-    http-proxy-middleware "^2.0.0"
-    internal-ip "^6.2.0"
+    http-proxy-middleware "^2.0.3"
     ipaddr.js "^2.0.1"
     open "^8.0.9"
     p-retry "^4.5.0"
-    portfinder "^1.0.28"
-    schema-utils "^3.1.0"
-    selfsigned "^1.10.11"
+    rimraf "^3.0.2"
+    schema-utils "^4.0.0"
+    selfsigned "^2.0.1"
     serve-index "^1.9.1"
-    sockjs "^0.3.21"
+    sockjs "^0.3.24"
     spdy "^4.0.2"
-    strip-ansi "^7.0.0"
-    url "^0.11.0"
-    webpack-dev-middleware "^5.0.0"
-    ws "^8.1.0"
+    webpack-dev-middleware "^5.3.1"
+    ws "^8.4.2"
 
 webpack-merge@^5.7.3:
   version "5.8.0"
@@ -8191,40 +8460,40 @@ webpack-node-externals@^3.0.0:
   resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917"
   integrity sha512-LnL6Z3GGDPht/AigwRh2dvL9PQPFQ8skEpVrWZXLWBYmqcaojHNN0onvHzie6rq7EWKrrBfPYqNEzTJgiwEQDQ==
 
-webpack-sources@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.0.tgz#b16973bcf844ebcdb3afde32eda1c04d0b90f89d"
-  integrity sha512-fahN08Et7P9trej8xz/Z7eRu8ltyiygEo/hnRi9KqBUs80KeDcnf96ZJo++ewWd84fEf3xSX9bp4ZS9hbw0OBw==
+webpack-sources@^3.2.3:
+  version "3.2.3"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+  integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
 
-webpack@5.51.1:
-  version "5.51.1"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.51.1.tgz#41bebf38dccab9a89487b16dbe95c22e147aac57"
-  integrity sha512-xsn3lwqEKoFvqn4JQggPSRxE4dhsRcysWTqYABAZlmavcoTmwlOb9b1N36Inbt/eIispSkuHa80/FJkDTPos1A==
+webpack@5.74.0:
+  version "5.74.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.74.0.tgz#02a5dac19a17e0bb47093f2be67c695102a55980"
+  integrity sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==
   dependencies:
-    "@types/eslint-scope" "^3.7.0"
-    "@types/estree" "^0.0.50"
+    "@types/eslint-scope" "^3.7.3"
+    "@types/estree" "^0.0.51"
     "@webassemblyjs/ast" "1.11.1"
     "@webassemblyjs/wasm-edit" "1.11.1"
     "@webassemblyjs/wasm-parser" "1.11.1"
-    acorn "^8.4.1"
+    acorn "^8.7.1"
     acorn-import-assertions "^1.7.6"
     browserslist "^4.14.5"
     chrome-trace-event "^1.0.2"
-    enhanced-resolve "^5.8.0"
-    es-module-lexer "^0.7.1"
+    enhanced-resolve "^5.10.0"
+    es-module-lexer "^0.9.0"
     eslint-scope "5.1.1"
     events "^3.2.0"
     glob-to-regexp "^0.4.1"
-    graceful-fs "^4.2.4"
-    json-parse-better-errors "^1.0.2"
+    graceful-fs "^4.2.9"
+    json-parse-even-better-errors "^2.3.1"
     loader-runner "^4.2.0"
     mime-types "^2.1.27"
     neo-async "^2.6.2"
     schema-utils "^3.1.0"
     tapable "^2.1.1"
     terser-webpack-plugin "^5.1.3"
-    watchpack "^2.2.0"
-    webpack-sources "^3.2.0"
+    watchpack "^2.4.0"
+    webpack-sources "^3.2.3"
 
 websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
   version "0.7.4"
@@ -8240,6 +8509,19 @@ websocket-extensions@>=0.1.1:
   resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
   integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
 
+websocket-ts@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/websocket-ts/-/websocket-ts-1.1.1.tgz#de482da5e0c714ebc58a43fe94157e5a855f2828"
+  integrity sha512-rm+S60J74Ckw5iizzgID12ju+OfaHAa6dhXhULIOrXkl0e05RzxfY42/vMStpz5jWL3iz9mkyjPcFUY1IgI0fw==
+
+whatwg-url@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+  integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0=
+  dependencies:
+    tr46 "~0.0.3"
+    webidl-conversions "^3.0.0"
+
 which-boxed-primitive@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6"
@@ -8263,7 +8545,7 @@ which@1, which@^1.2.9, which@^1.3.0, which@^1.3.1, which@~1.3.0:
   dependencies:
     isexe "^2.0.0"
 
-which@^2.0.1, which@^2.0.2:
+which@^2.0.1:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
   integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
@@ -8271,11 +8553,11 @@ which@^2.0.1, which@^2.0.2:
     isexe "^2.0.0"
 
 wide-align@^1.1.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
-  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3"
+  integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==
   dependencies:
-    string-width "^1.0.2 || 2"
+    string-width "^1.0.2 || 2 || 3 || 4"
 
 widest-line@^2.0.0:
   version "2.0.1"
@@ -8350,10 +8632,10 @@ write-file-atomic@^2.0.0, write-file-atomic@^2.3.0:
     imurmurhash "^0.1.4"
     signal-exit "^3.0.2"
 
-ws@^8.1.0, ws@^8.2.0:
-  version "8.2.0"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.0.tgz#0b738cd484bfc9303421914b11bb4011e07615bb"
-  integrity sha512-uYhVJ/m9oXwEI04iIVmgLmugh2qrZihkywG9y5FfZV2ATeLIzHf93qs+tUNqlttbQK957/VX3mtwAS+UfIwA4g==
+ws@^8.4.2:
+  version "8.5.0"
+  resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
+  integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
 
 xdg-basedir@^3.0.0:
   version "3.0.0"
@@ -8390,18 +8672,10 @@ yallist@^4.0.0:
   resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
   integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 
-yaml@^1.10.0:
-  version "1.10.2"
-  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
-  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
-
-yargs-parser@^13.1.2:
-  version "13.1.2"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"
-  integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==
-  dependencies:
-    camelcase "^5.0.0"
-    decamelize "^1.2.0"
+yaml@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
+  integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
 
 yargs-parser@^15.0.1:
   version "15.0.3"
@@ -8411,11 +8685,6 @@ yargs-parser@^15.0.1:
     camelcase "^5.0.0"
     decamelize "^1.2.0"
 
-yargs-parser@^20.2.3:
-  version "20.2.9"
-  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
-  integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
-
 yargs-parser@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9"
@@ -8423,22 +8692,6 @@ yargs-parser@^7.0.0:
   dependencies:
     camelcase "^4.1.0"
 
-yargs@^13.3.2:
-  version "13.3.2"
-  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd"
-  integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==
-  dependencies:
-    cliui "^5.0.0"
-    find-up "^3.0.0"
-    get-caller-file "^2.0.1"
-    require-directory "^2.1.1"
-    require-main-filename "^2.0.0"
-    set-blocking "^2.0.0"
-    string-width "^3.0.0"
-    which-module "^2.0.0"
-    y18n "^4.0.0"
-    yargs-parser "^13.1.2"
-
 yargs@^14.2.3:
   version "14.2.3"
   resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414"
@@ -8474,8 +8727,3 @@ yargs@^8.0.2:
     which-module "^2.0.0"
     y18n "^3.2.1"
     yargs-parser "^7.0.0"
-
-yocto-queue@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
-  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==